/*! @file
This file offers a C + + access to the PCSC library .
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# ifndef PCSC_HXX
# define PCSC_HXX
# include <cryptaux.hxx>
# include <string>
# if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
# undef UNICODE
# undef DATADIR
# include <winscard.h>
# undef ERROR
# ifndef MAX_ATR_SIZE
# define MAX_ATR_SIZE 33
# endif
namespace pcsc {
# ifdef UNICODE
inline std : : wstring strconv ( std : : string s ) {
return std : : wstring ( s . begin ( ) , s . end ( ) ) ;
}
inline std : : string strconv ( std : : wstring s ) {
return std : : string ( s . begin ( ) , s . end ( ) ) ;
}
typedef wchar_t char_t ;
typedef std : : wstring string ;
# else
inline const std : : string & strconv ( const std : : string & s ) {
return s ;
}
typedef char char_t ;
typedef std : : string string ;
# endif
}
# else
# include <PCSC/pcsclite.h>
# include <PCSC/wintypes.h>
# include <PCSC/winscard.h>
namespace pcsc {
inline const std : : string & strconv ( const std : : string & s ) {
return s ;
}
typedef char char_t ;
typedef std : : string string ;
}
# endif
# include <vector>
# include <map>
# include <mrw/checkcxx11.hxx>
# include <memory>
# include <sstream>
# include <iomanip>
/*! @defgroup gpcsc C++ Wrapper around pcsc-lite API
This library is a C + + wrapper to the awful pcsc - lite interface .
The reason for this wrapper is to get a nice object oriented
interface written in C + + manner and using standard types and so to
avoid the ugly M $ - C - quirks . This interface is memory clean .
@ todo : Not implemented , not supported :
- SCardGetStatusChange ( hContext , 0 , rgReaderStates , 1 ) ;
- several other
I do not need these , and I don ' t know the usecase where they are
required . If you need something that is not yet supported , please
let me know , what you need and why . Then I ' ll add it so that it
best fits the common needs . */
//@{
/*! @defgroup pcsclib PCSC C++ Library */
/*! @defgroup pcscexceptions PCSC Exceptions */
//! @ref gpcsc @copydoc gpcsc
namespace pcsc {
//============================================================================
//! @addtogroup pcscexceptions
//@{
//----------------------------------------------------------------------------
class exception : public std : : exception {
public :
exception ( const std : : string & reason ) throw ( ) : _what ( " pcsc: " + reason ) {
CRYPTOLOG ( " ERROR: " < < what ( ) ) ;
}
~ exception ( ) throw ( ) { }
const char * what ( ) const throw ( ) {
return _what . c_str ( ) ;
}
private :
std : : string _what ;
} ;
//----------------------------------------------------------------------------
class not_implemented : public exception {
public :
not_implemented ( const std : : string & reason ) throw ( ) :
exception ( " feature is not implemented: " + reason ) {
}
} ;
//----------------------------------------------------------------------------
class access_error : public exception {
public :
access_error ( const std : : string & reason ) throw ( ) :
exception ( " smardcard access error: " + reason ) {
}
} ;
//----------------------------------------------------------------------------
class wrong_pin : public access_error {
public :
wrong_pin ( const std : : string & reason ) throw ( ) :
access_error ( " wrong pin: " + reason ) {
}
} ;
//----------------------------------------------------------------------------
class runtime_error : public exception {
public :
runtime_error ( const std : : string & reason , const std : : string & data ) throw ( ) :
exception ( " runtime error, " + reason + " : " + crypto : : hex ( data ) ) { }
} ;
//----------------------------------------------------------------------------
class neesting_error : public exception {
public :
neesting_error ( ) throw ( ) :
exception ( " neesting error: more endTransaction than beginTransaction " )
{ }
} ;
//@}
//! @addtogroup pcsclib
//@{
//============================================================================
class Connection {
//...............................................................typedefs
public :
//------------------------------------------------------------------Reader
friend class Reader ;
class Reader {
//............................................................typedefs
public :
friend class Transaction ;
//! Scoped transaction.
/*! This is a scoped transaction. That means, the
transaction is started in the constructor and ended in
the destructor , unless it is already ended before . In
case of an exception or leaving the block , the
transaction is always cleaned up .
There ' s a neesting counter to make sure , transaction is
started only once and ended only once , even though the
locking can be neested .
@ code
pcsc : : Connection c ;
{
Transaction t ( c . reader ( " name " ) ) ;
[ . . . ] // do some stuff, possible exceptions thrown
if ( problem ) return ; // automatically ended
[ . . . ]
t . end ( ) ; // ended if we reach this line
[ . . . ]
} // also ended, unless commit reaced
@ endcode */
class Transaction {
public :
//! Begins a transaction.
/*! @note Please note that the Reader is required in the
destructor und must therefore live longer than the
Transaction instance . */
Transaction ( std : : shared_ptr < Reader > r ) :
_reader ( r ) , _running ( true ) {
CRYPTOLOG ( " log " ) ;
_reader - > beginTransaction ( ) ;
}
//! Cancels the transaction if not yet finished.
~ Transaction ( ) try {
CRYPTOLOG ( " log " ) ;
end ( ) ;
} catch ( . . . ) {
if ( ! std : : uncaught_exception ( ) ) throw ;
}
//! Ends the running transaction.
void end ( ) {
if ( _running ) _reader - > endTransaction ( ) ;
_running = false ;
}
private :
std : : shared_ptr < Reader > _reader ;
bool _running ;
} ;
//! State and attribute list of a reader.
class Status {
public :
Status ( DWORD s , const std : : string & a ) :
state ( s ) , atr ( a ) { }
const DWORD state ;
const std : : string atr ;
} ;
//.............................................................methods
public :
//! Disconnects connection.
~ Reader ( ) {
CRYPTOLOG ( " Disconnect Reader " ) ;
_state = SCardDisconnect ( _id , SCARD_RESET_CARD ) ;
if ( ! std : : uncaught_exception ( ) )
_connection - > check ( _state , " disconnect smartcard " ) ;
}
//! Get reader status.
Status status ( ) {
DWORD dummy ( 0 ) ;
DWORD s ;
DWORD len ( MAX_ATR_SIZE ) ;
unsigned char a [ MAX_ATR_SIZE ] ;
check ( SCardStatus ( _id , 0 , & dummy , & s , & _protocol , a , & len ) ,
" query smartcard status " ) ;
return Status ( s , std : : string ( ( char * ) a , len ) ) ;
}
//! Transmit data to reader.
/*! @note Take care: Stings may contain embedded @c 0. */
std : : string transmit ( char cla , char ins , char p1 , char p2 ,
const std : : string & lc = std : : string ( ) ,
unsigned char le = 253 ) {
std : : string claInsP1P2 ;
claInsP1P2 . push_back ( cla ) ;
claInsP1P2 . push_back ( ins ) ;
claInsP1P2 . push_back ( p1 ) ;
claInsP1P2 . push_back ( p2 ) ;
return transmit ( claInsP1P2 , lc , le ) ;
}
//! Transmit data to reader.
/*! @note Take care: Stings may contain embedded @c 0. */
std : : string transmit ( char cla , char ins , char p1 , char p2 ,
unsigned char le ) {
std : : string claInsP1P2 ;
claInsP1P2 . push_back ( cla ) ;
claInsP1P2 . push_back ( ins ) ;
claInsP1P2 . push_back ( p1 ) ;
claInsP1P2 . push_back ( p2 ) ;
return transmit ( claInsP1P2 , std : : string ( ) , le ) ;
}
//! Transmit data to reader.
/*! @note Take care: Stings may contain embedded @c 0. */
std : : string transmit ( char cla , char ins , char p1 , char p2 ,
const char * lc , int len ,
unsigned char le = 253 ) {
std : : string claInsP1P2 ;
claInsP1P2 . push_back ( cla ) ;
claInsP1P2 . push_back ( ins ) ;
claInsP1P2 . push_back ( p1 ) ;
claInsP1P2 . push_back ( p2 ) ;
return transmit ( claInsP1P2 , std : : string ( lc , len ) , le ) ;
}
//! Transmit data to reader.
/*! @note Take care: Stings may contain embedded @c 0.
@ note Prefer the transmit methods that passes @ c cla , @ c
ins , @ c p1 and @ c p2 separate . */
std : : string transmit ( const std : : string & claInsP1P2 ,
const std : : string & lc ,
unsigned char le = 253 ) {
if ( claInsP1P2 . size ( ) ! = 4 )
throw runtime_error ( " transmit: claInsP1P2 must be 4 byte " ,
claInsP1P2 ) ;
if ( lc . size ( ) > 255 ) throw runtime_error ( " transmit: lc too long " , lc ) ;
std : : string msg ( claInsP1P2 ) ;
if ( lc . size ( ) ) ( msg + = ( char ) lc . size ( ) ) + = lc ;
msg + = le ;
return transmit ( msg ) ;
}
//! Transmit data to reader.
/*! @note Take care: Stings may contain embedded @c 0.
@ note Prefer the transmit methods that passes @ c cla , @ c
ins , @ c p1 and @ c p2 separate . */
std : : string transmit ( std : : string in ) {
const DWORD bufflen ( 1024 ) ;
DWORD len ( bufflen ) ; // arbitrary
unsigned char buff [ bufflen ] ;
SCARD_IO_REQUEST rPci ;
rPci . dwProtocol = pci ( ) - > dwProtocol ;
rPci . cbPciLength = sizeof ( rPci ) ;
// log only in verbose debuggung; could log pins
CRYPTOLOG_VERBOSE ( " SCardTransmit: " < < crypto : : hex ( in ) ) ;
try {
check ( SCardTransmit ( _id , & rPci ,
( LPCBYTE ) in . c_str ( ) ,
in . size ( ) ,
0 , buff , & len ) ,
" smartcard transmit message " + crypto : : hex ( in ) ) ;
} catch ( std : : exception & x ) {
CRYPTOLOG ( " failed with " < < x . what ( ) ) ;
// try to fix Apple's Mac OS X 10.10 implementation bug
# ifdef __APPLE__
/*! @bug Work around Mac OSX 10.10 bug. On Mac OSX
10.10 there is a bug in PCSC : After a
reconnect , first transaction ( SCardTransmit )
fails with SCARD_W_RESET_CARD
( 0x80100068 ) . */
for ( int cnt ( 0 ) ; cnt < 10 & & _state = = SCARD_W_RESET_CARD ; + + cnt ) {
// just try to resend
CRYPTOLOG ( " Mac OS X 10.10 implementation bug: "
" On Mac OSX 10.10 there is a bug in "
" PCSC: After a reconnect, first "
" transaction (SCardTransmit) fails "
" with SCARD_W_RESET_CARD (0x80100068). "
" Retry Nr. " < < cnt ) ;
try {
reconnect ( ) ;
if ( check ( SCardTransmit ( _id , & rPci ,
( LPCBYTE ) in . c_str ( ) ,
in . size ( ) ,
0 , buff , & len ) ,
" smartcard transmit resend message "
+ crypto : : hex ( in ) ) ) {
CRYPTOLOG ( " successful after retry nr. " < < cnt ) ;
return std : : string ( ( char * ) buff , len ) ;
}
} catch ( std : : exception & x ) {
CRYPTOLOG ( " failed again with " < < x . what ( ) ) ;
}
}
# endif
CRYPTOLOG ( " definitely failed with " < < x . what ( ) ) ;
throw ; // just rethrow otherwise
}
//CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)buff, len)));
return std : : string ( ( char * ) buff , len ) ;
}
//! Transmit control command and data to the reader.
/*!
* @ note Take care : Strings may contain embedded @ c 0.
*/
std : : string control ( DWORD controlCode ,
std : : string in ) {
DWORD len ( 256 ) ; // arbitrary
UCHAR dataBuffer [ 256 ] ;
CRYPTOLOG ( " SCardControl: " < < " Command: " < < controlCode ) ;
CRYPTOLOG ( " -> " < < crypto : : hex ( in ) ) ;
check ( SCardControl ( _id , controlCode ,
( LPCBYTE ) in . c_str ( ) , in . size ( ) ,
dataBuffer , sizeof ( dataBuffer ) , & len ) ,
" smartcard control message sent " ) ;
CRYPTOLOG ( " -> " < < crypto : : hex ( std : : string ( ( char * ) dataBuffer , len ) ) ) ;
return std : : string ( ( char * ) dataBuffer , len ) ;
}
//! @c false if last operation was not successful
operator bool ( ) const {
// Values are 32 bit values layed out as follows:
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// ---+-+-+-----------------------+-------------------------------
// Sev|C|R| Facility | Code
// ---+-+-+-----------------------+-------------------------------
// where Sev - is the severity code
// 00 - Success
// 01 - Informational
// 10 - Warning
// 11 - Error
// So everything with Sev=00 is successful
// theoretically even with Sev=01, but that's still rejected
//return (_state>>30&3)==0;
return _state = = SCARD_S_SUCCESS ;
}
//...........................................................variables
public :
const std : : string name ;
//.............................................................methods
private :
//! Use scoped transactions with @ref Transaction
/*! Calls @c SCardBeginTransaction unless it's already inside
a transaction . */
void beginTransaction ( ) {
if ( + + _neesting = = 1 ) {
CRYPTOLOG ( " open transaction " ) ;
check ( SCardBeginTransaction ( _id ) , " smartcard begin transaction " ) ;
}
}
//! Use scoped transactions with @ref Transaction
/*! Calls @c SCardEndTransaction if it's inside a transaction.
@ throws neesting_error if there are more calls to @ c
endTransaction than to @ c beginTransaction . */
void endTransaction ( ) {
if ( - - _neesting = = 0 ) {
CRYPTOLOG ( " close transaction " ) ;
check ( SCardEndTransaction ( _id , SCARD_LEAVE_CARD ) ,
" smartcard end transaction " ) ;
} else if ( _neesting < 0 ) {
_neesting = 0 ;
throw neesting_error ( ) ;
}
}
/*! @throw not_implemented if _protocol is unknown. */
const SCARD_IO_REQUEST * pci ( ) {
switch ( _protocol ) {
case SCARD_PROTOCOL_T0 : return SCARD_PCI_T0 ;
case SCARD_PROTOCOL_T1 : return SCARD_PCI_T1 ;
}
if ( _connection - > exc ( ) ) throw not_implemented ( " unknown protocol " ) ;
return 0 ;
}
//! Sets state and throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command . */
bool check ( DWORD state , const std : : string context = " " ) {
_state = state ;
return _connection - > check ( state , context ) ;
}
//! Reconnect SmartCard After Reset
/*! @param mode one of
- @ c SCARD_LEAVE_CARD
Do not do anything special on reconnect .
- @ c SCARD_RESET_CARD
Reset the card ( Warm Reset ) .
- @ c SCARD_UNPOWER_CARD
Power down the card and reset it ( Cold Reset ) . */
void reconnect ( DWORD mode = SCARD_LEAVE_CARD ) {
check ( SCardReconnect ( _id , _mode , _protocol , mode , & _protocol ) ) ;
}
//! Only Connection is allowed to instanciate.
friend class Connection ;
//! Establishes a connection to the given named cardreader
Reader ( const std : : string & nm , std : : shared_ptr < Connection > c ,
DWORD mode = SCARD_SHARE_SHARED ,
DWORD protocol = SCARD_PROTOCOL_T1 ) :
name ( nm ) , _connection ( c ) , _mode ( mode ) {
CRYPTOLOG ( " Connect Reader " ) ;
check ( SCardConnect ( _connection - > id ( ) , strconv ( name ) . c_str ( ) ,
_mode , protocol ,
& _id , & _protocol ) ,
" connect smartcard \" " + name + " \" " ) ;
}
//! forbidden
Reader ( ) ;
//...........................................................variables
private :
std : : shared_ptr < Connection > _connection ;
SCARDHANDLE _id ;
DWORD _state ;
DWORD _mode ;
DWORD _protocol ;
static int _neesting ;
} ;
//------------------------------------------------------------------Reader
enum Scope {
USER = SCARD_SCOPE_USER ,
TERMINAL = SCARD_SCOPE_TERMINAL ,
SYSTEM = SCARD_SCOPE_SYSTEM
} ;
typedef std : : vector < std : : string > Strings ;
//................................................................methods
public :
//! Closes the connection (releases the smartcard context)
~ Connection ( ) {
CRYPTOLOG ( " Close Connection id= " < < _id ) ;
_state = SCardReleaseContext ( _id ) ;
if ( ! std : : uncaught_exception ( ) ) check ( " smartcard release context " ) ;
}
//! Scans for available readers from a specified list of groups.
/*! Defaults to all groups. */
static Strings scan ( const Strings & groups = Strings ( ) ,
Scope s = USER , bool exceptions = true ) {
Connection c ( s , exceptions ) ;
Strings res ;
std : : string grp ( c . join ( groups ) ) ;
DWORD num ( 0 ) ;
if ( ! c . check ( SCardListReaders ( c . _id ,
groups . size ( ) ? strconv ( grp ) . data ( ) : 0 , 0 ,
& num ) ,
" smartcard get size of readers of groups " + grp ) )
return res ;
CRYPTOLOG ( " size of readers: " < < num ) ;
if ( ! num ) return res ;
std : : auto_ptr < char_t > nm ( new char_t [ num ] ) ;
if ( ! c . check ( SCardListReaders ( c . _id ,
groups . size ( ) ? strconv ( grp ) . data ( ) : 0 ,
nm . get ( ) , & num ) ,
" smartcard list reader names of groups " + grp ) )
return res ;
CRYPTOLOG ( " got all readers, size is " < < num ) ;
if ( ! num ) return res ;
CRYPTOLOG ( " list of readers: "
< < crypto : : readable ( std : : string ( nm . get ( ) , num - 1 ) ) ) ;
return res = c . split ( strconv ( string ( nm . get ( ) , num - 1 ) ) ) ;
}
//! Find all readers with a given ATR.
/*! @param atr full or partial ATR to match to the reader's ATR
@ param s scope of scanning
@ param exceptions whether exeptions should be thrown on error
@ returns list of readers that contain @ c atr in their ATR */
static Strings getReadersWithAtr ( const std : : string & atr ,
Scope s = USER , bool exceptions = true ) {
CRYPTOLOG ( " getting all readers with atr: " < < atr ) ;
Connection c ( s , exceptions ) ;
Strings res ;
pcsc : : Connection : : Strings readers ( c . scan ( ) ) ;
for ( pcsc : : Connection : : Strings : : const_iterator it ( readers . begin ( ) ) ;
it ! = readers . end ( ) ; + + it )
try {
if ( crypto : : hex ( c . reader ( * it ) - > status ( ) . atr ) . find ( atr )
! = string : : npos )
CRYPTOLOG ( " found reader: " < < ( * it ) ) ;
res . push_back ( * it ) ;
} catch ( std : : exception & x ) { // ignore unusable readers
CRYPTOLOG ( " ignored unusable reader: " < < x . what ( ) ) ;
}
return res ;
}
//! Get a reader, open a connection if not already open.
/*! First use scan() to get a list of readers, then open a
connection to the reader , then access it . */
static std : : shared_ptr < Reader > reader ( const std : : string & name ,
Scope s = USER , bool exceptions = true ) {
CRYPTOLOG ( " get reader: " < < name ) ;
return std : : shared_ptr < Reader >
( new Reader ( name ,
std : : shared_ptr < Connection >
( new Connection ( s , exceptions ) ) ) ) ;
}
//................................................................methods
private :
//! Opens a connection (establishes a smartcard context)
/*! The errorhandling is defined with the @c exceptions flag:
Using exceptions :
@ code
try {
pcsc : : Connection c ; // standard with exceptions
pcsc : : Connection : : Strings r ( c . scan ( ) ) ;
} catch ( std : : exception & x ) {
std : : cout < < " Error with message: " < < x . what ( ) < < std : : endl ;
}
@ endcode
Without exceptions :
@ code
pcsc : : Connection c ( SYSTEM , false ) ;
if ( ! c ) std : : cout < < " Error with message: " < < c . error ( ) < < std : : endl ;
pcsc : : Connection : : Strings r ( c . scan ( ) ) ;
if ( ! c ) std : : cout < < " Error with message: " < < c . error ( ) < < std : : endl ;
@ endcode
Recommendation : Use exceptions !
@ param s defines the scope of the connection
@ param exceptions
- @ c true : class throws exceptions in case of an error
- @ c false : no exceptions , check your instance after each
operation */
Connection ( Scope s = USER , bool exceptions = true ) :
_exc ( exceptions ) , _id ( 0 ) , _s ( s ) ,
_state ( SCardEstablishContext ( s , 0 , 0 , & _id ) ) {
CRYPTOLOG ( " Open Connection id= " < < _id ) ;
check ( " establish smartcard context " ) ;
}
//! Splits a buffer with 0 separators into a vector of strings.
static Strings split ( const std : : string & in ) {
Strings res ;
for ( std : : string : : size_type pos ( 0 ) ; pos < in . size ( ) & & in [ pos ] ! = 0 ;
pos + = res . rbegin ( ) - > size ( ) + 1 )
res . push_back ( in . substr ( pos ) . c_str ( ) ) ;
return res ;
}
//! Joins a vector of strings into a buffer with 0 separators.
static std : : string join ( const Strings & in ) {
std : : string res ;
if ( in . size ( ) ) {
for ( Strings : : const_iterator it ( in . begin ( ) ) ;
it ! = in . end ( ) ; + + it )
res + = * it + ' \0 ' ;
res + = ' \0 ' ;
}
return res ;
}
operator bool ( ) const {
# ifdef WIN32
return ( _state > > 30 & 3 ) = = 0 ;
# else
return _state = = SCARD_S_SUCCESS ;
# endif
}
//! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command . */
bool check ( DWORD s , const std : : string & context = " " ) {
_state = s ;
return check ( context ) ;
}
//! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command . */
bool check ( const std : : string & context = " " ) {
if ( _exc & & ! * this ) {
if ( context . size ( ) ) {
# ifdef SCARD_W_WRONG_CHV
if ( _state = = SCARD_W_WRONG_CHV ) {
throw wrong_pin ( context + " : " + error ( ) ) ;
} else {
# endif
throw access_error ( context + " : " + error ( ) ) ;
# ifdef SCARD_W_WRONG_CHV
}
# endif
} else {
# ifdef SCARD_W_WRONG_CHV
if ( _state = = SCARD_W_WRONG_CHV ) {
throw wrong_pin ( error ( ) ) ;
} else {
# endif
throw access_error ( error ( ) ) ;
# ifdef SCARD_W_WRONG_CHV
}
# endif
}
}
return * this ;
}
//! Get the describing text of the last error
std : : string error ( ) const {
std : : stringstream ss ;
switch ( _state ) {
# ifdef SCARD_E_CANCELLED
case SCARD_E_CANCELLED :
ss < < " The action was canceled by an SCardCancel request. " ;
break ;
# endif
# ifdef SCARD_E_CANT_DISPOSE
case SCARD_E_CANT_DISPOSE :
ss < < " The system could not dispose of the media in the requested "
< < " manner. " ;
break ;
# endif
# ifdef SCARD_E_CARD_UNSUPPORTED
case SCARD_E_CARD_UNSUPPORTED :
ss < < " The smart card does not meet minimal requirements for "
< < " support. " ;
break ;
# endif
# ifdef SCARD_E_DUPLICATE_READER
case SCARD_E_DUPLICATE_READER :
ss < < " The reader driver did not produce a unique reader name. " ;
break ;
# endif
# ifdef SCARD_E_INSUFFICIENT_BUFFER
case SCARD_E_INSUFFICIENT_BUFFER :
ss < < " The data buffer for returned data is too small for the "
< < " returned data. " ;
break ;
# endif
# ifdef SCARD_E_INVALID_ATR
case SCARD_E_INVALID_ATR :
ss < < " An ATR string obtained from the registry is not a valid "
< < " ATR string. " ;
break ;
# endif
# ifdef SCARD_E_INVALID_HANDLE
case SCARD_E_INVALID_HANDLE :
ss < < " The supplied handle was not valid. " ;
break ;
# endif
# ifdef SCARD_E_INVALID_PARAMETER
case SCARD_E_INVALID_PARAMETER :
ss < < " One or more of the supplied parameters could not be properly "
< < " interpreted. " ;
break ;
# endif
# ifdef SCARD_E_INVALID_TARGET
case SCARD_E_INVALID_TARGET :
ss < < " Registry startup information is missing or not valid. " ;
break ;
# endif
# ifdef SCARD_E_INVALID_VALUE
case SCARD_E_INVALID_VALUE :
ss < < " One or more of the supplied parameters values could not "
< < " be properly interpreted. " ;
break ;
# endif
# ifdef SCARD_E_NOT_READY
case SCARD_E_NOT_READY :
ss < < " The reader or smart card is not ready to accept commands. " ;
break ;
# endif
# ifdef SCARD_E_NOT_TRANSACTED
case SCARD_E_NOT_TRANSACTED :
ss < < " An attempt was made to end a nonexistent transaction. " ;
break ;
# endif
# ifdef SCARD_E_NO_MEMORY
case SCARD_E_NO_MEMORY :
ss < < " Not enough memory available to complete this command. " ;
break ;
# endif
# ifdef SCARD_E_NO_SERVICE
case SCARD_E_NO_SERVICE :
ss < < " The smart card resource manager is not running. " ;
break ;
# endif
# ifdef SCARD_E_NO_SMARTCARD
case SCARD_E_NO_SMARTCARD :
ss < < " The operation requires a smart card, but no smart card "
< < " is currently in the device. " ;
break ;
# endif
# ifdef SCARD_E_PCI_TOO_SMALL
case SCARD_E_PCI_TOO_SMALL :
ss < < " The PCI receive buffer was too small. " ;
break ;
# endif
# ifdef SCARD_E_PROTO_MISMATCH
case SCARD_E_PROTO_MISMATCH :
ss < < " The requested protocols are incompatible with the protocol "
< < " currently in use with the smart card. " ;
break ;
# endif
# ifdef SCARD_E_READER_UNAVAILABLE
case SCARD_E_READER_UNAVAILABLE :
ss < < " The specified reader is not currently available for use. " ;
break ;
# endif
# ifdef SCARD_E_READER_UNSUPPORTED
case SCARD_E_READER_UNSUPPORTED :
ss < < " The reader driver does not meet minimal requirements for "
< < " support. " ;
break ;
# endif
# ifdef SCARD_E_SERVICE_STOPPED
case SCARD_E_SERVICE_STOPPED :
ss < < " The smart card resource manager has shut down. " ;
break ;
# endif
# ifdef SCARD_E_SHARING_VIOLATION
case SCARD_E_SHARING_VIOLATION :
ss < < " The smart card cannot be accessed because of other "
< < " outstanding connections. " ;
break ;
# endif
# ifdef SCARD_E_SYSTEM_CANCELLED
case SCARD_E_SYSTEM_CANCELLED :
ss < < " The action was cancelled by the system, presumably to log "
< < " off or shut down. " ;
break ;
# endif
# ifdef SCARD_E_TIMEOUT
case SCARD_E_TIMEOUT :
ss < < " The user-specified time-out value has expired. " ;
break ;
# endif
# ifdef SCARD_E_UNKNOWN_CARD
case SCARD_E_UNKNOWN_CARD :
ss < < " The specified smart card name is not recognized. " ;
break ;
# endif
# ifdef SCARD_E_UNKNOWN_READER
case SCARD_E_UNKNOWN_READER :
ss < < " The specified reader name is not recognized. " ;
break ;
# endif
# ifdef SCARD_F_COMM_ERROR
case SCARD_F_COMM_ERROR :
ss < < " An internal communications error has been detected. " ;
break ;
# endif
# ifdef SCARD_F_INTERNAL_ERROR
case SCARD_F_INTERNAL_ERROR :
ss < < " An internal consistency check failed. " ;
break ;
# endif
# ifdef SCARD_F_UNKNOWN_ERROR
case SCARD_F_UNKNOWN_ERROR :
ss < < " An internal error has been detected, but the source is "
< < " unknown. " ;
break ;
# endif
# ifdef SCARD_F_WAITED_TOO_LONG
case SCARD_F_WAITED_TOO_LONG :
ss < < " An internal consistency timer has expired. " ;
break ;
# endif
# ifdef SCARD_S_SUCCESS
case SCARD_S_SUCCESS :
ss < < " No error was encountered. " ;
break ;
# endif
# ifdef SCARD_W_REMOVED_CARD
case SCARD_W_REMOVED_CARD :
ss < < " The smart card has been removed, so that further "
< < " communication is not possible. " ;
break ;
# endif
# ifdef SCARD_W_RESET_CARD
case SCARD_W_RESET_CARD :
ss < < " The smart card was reset. " ;
break ;
# endif
# ifdef SCARD_W_UNPOWERED_CARD
case SCARD_W_UNPOWERED_CARD :
ss < < " Power has been removed from the smart card, so that "
< < " further communication is not possible. " ;
break ;
# endif
# ifdef SCARD_W_UNRESPONSIVE_CARD
case SCARD_W_UNRESPONSIVE_CARD :
ss < < " The smart card is not responding to a reset. " ;
break ;
# endif
# ifdef SCARD_W_UNSUPPORTED_CARD
case SCARD_W_UNSUPPORTED_CARD :
ss < < " The reader cannot communicate with the smart card, "
< < " due to ATR configuration conflicts. " ;
break ;
# endif
# ifdef SCARD_E_NO_READERS_AVAILABLE
case SCARD_E_NO_READERS_AVAILABLE :
ss < < " No smart card reader is available. " ;
break ;
# endif
# ifdef ERROR_BROKEN_PIPE
case ERROR_BROKEN_PIPE :
ss < < " The client attempted a smart card operation in a "
< < " remote session, such as a client session running "
< < " on a terminal server, and the operating system in "
< < " use does not support smart card redirection. " ;
break ;
# endif
# ifdef SCARD_E_BAD_SEEK
case SCARD_E_BAD_SEEK :
ss < < " There was an error trying to set the smart card file "
< < " object pointer. " ;
break ;
# endif
# ifdef SCARD_E_CERTIFICATE_UNAVAILABLE
case SCARD_E_CERTIFICATE_UNAVAILABLE :
ss < < " The requested certificate could not be obtained. " ;
break ;
# endif
# ifdef SCARD_E_COMM_DATA_LOST
case SCARD_E_COMM_DATA_LOST :
ss < < " A communications error with the smart card has been detected. " ;
break ;
# endif
# ifdef SCARD_E_DIR_NOT_FOUND
case SCARD_E_DIR_NOT_FOUND :
ss < < " The specified directory does not exist in the smart card. " ;
break ;
# endif
# ifdef SCARD_E_FILE_NOT_FOUND
case SCARD_E_FILE_NOT_FOUND :
ss < < " The specified file does not exist in the smart card. " ;
break ;
# endif
# ifdef SCARD_E_ICC_CREATEORDER
case SCARD_E_ICC_CREATEORDER :
ss < < " The requested order of object creation is not supported. " ;
break ;
# endif
# ifdef SCARD_E_ICC_INSTALLATION
case SCARD_E_ICC_INSTALLATION :
ss < < " No primary provider can be found for the smart card. " ;
break ;
# endif
# ifdef SCARD_E_INVALID_CHV
case SCARD_E_INVALID_CHV :
ss < < " The supplied PIN is incorrect. " ;
break ;
# endif
# ifdef SCARD_E_NO_ACCESS
case SCARD_E_NO_ACCESS :
ss < < " Access is denied to this file. " ;
break ;
# endif
# ifdef SCARD_E_NO_DIR
case SCARD_E_NO_DIR :
ss < < " The supplied path does not represent a smart card directory. " ;
break ;
# endif
# ifdef SCARD_E_NO_FILE
case SCARD_E_NO_FILE :
ss < < " The supplied path does not represent a smart card file. " ;
break ;
# endif
# ifdef SCARD_E_NO_KEY_CONTAINER
case SCARD_E_NO_KEY_CONTAINER :
ss < < " The requested key container does not exist on the smart card. " ;
break ;
# endif
# ifdef SCARD_E_NO_SUCH_CERTIFICATE
case SCARD_E_NO_SUCH_CERTIFICATE :
ss < < " The requested certificate does not exist. " ;
break ;
# endif
# ifdef SCARD_E_SERVER_TOO_BUSY
case SCARD_E_SERVER_TOO_BUSY :
ss < < " The Smart card resource manager is too busy to complete this "
< < " operation. " ;
break ;
# endif
# ifdef SCARD_E_UNSUPPORTED_FEATURE
case SCARD_E_UNSUPPORTED_FEATURE :
ss < < " This smart card does not support the requested feature. " ;
break ;
# else
# ifdef SCARD_E_UNEXPECTED
case SCARD_E_UNEXPECTED :
ss < < " An unexpected card error has occurred. " ;
break ;
# endif
# endif
# ifdef SCARD_E_UNKNOWN_RES_MNG
case SCARD_E_UNKNOWN_RES_MNG :
ss < < " An unrecognized error code was returned from a layered "
< < " component. " ;
break ;
# endif
# ifdef SCARD_E_WRITE_TOO_MANY
case SCARD_E_WRITE_TOO_MANY :
ss < < " The smartcard does not have enough memory to store the "
< < " information. " ;
break ;
# endif
# ifdef SCARD_P_SHUTDOWN
case SCARD_P_SHUTDOWN :
ss < < " The operation has been aborted to allow the server application "
< < " to exit. " ;
break ;
# endif
# ifdef SCARD_W_CANCELLED_BY_USER
case SCARD_W_CANCELLED_BY_USER :
ss < < " The action was cancelled by the user. " ;
break ;
# endif
# ifdef SCARD_W_CARD_NOT_AUTHENTICATED
case SCARD_W_CARD_NOT_AUTHENTICATED :
ss < < " No PIN was presented to the smart card. " ;
break ;
# endif
# ifdef SCARD_W_CHV_BLOCKED
case SCARD_W_CHV_BLOCKED :
ss < < " The card cannot be accessed because the maximum number "
< < " of PIN entry attempts has been reached. " ;
break ;
# endif
# ifdef SCARD_W_EOF
case SCARD_W_EOF :
ss < < " The end of the smart card file has been reached. " ;
break ;
# endif
# ifdef SCARD_W_SECURITY_VIOLATION
case SCARD_W_SECURITY_VIOLATION :
ss < < " Access was denied because of a security violation. " ;
break ;
# endif
# ifdef SCARD_W_WRONG_CHV
case SCARD_W_WRONG_CHV :
ss < < " The card cannot be accessed because the wrong PIN was "
< < " presented. " ;
break ;
# endif
default :
ss < < " unknown PCSC state=0x "
< < std : : hex < < std : : setfill ( ' 0 ' ) < < std : : setw ( 8 ) < < _state ;
switch ( _state > > 30 ) {
case 0 : ss < < " means SUCCESS " ; break ;
case 1 : ss < < " means INFORMATIONAL " ; break ;
case 2 : ss < < " means WARNING " ; break ;
case 3 : ss < < " means ERROR " ; break ;
default : ss < < " illegal value " ;
}
ss < < " C= " < < ( _state > > 29 & 1 ) ;
ss < < " R= " < < ( _state > > 28 & 1 ) ;
ss < < " Facility=0x " < < std : : hex < < std : : setfill ( ' 0 ' ) < < std : : setw ( 3 )
< < ( _state > > 16 & 0xfff ) ;
ss < < " Code=0x " < < std : : hex < < std : : setfill ( ' 0 ' ) < < std : : setw ( 4 )
< < ( _state & 0xffff ) ;
}
return ss . str ( ) ;
}
//! set state
void state ( DWORD s ) {
_state = s ;
}
//! @returns state
DWORD state ( ) {
return _state ;
}
//! @returns connection id
SCARDCONTEXT id ( ) {
return _id ;
}
bool exc ( ) {
return _exc ;
}
private :
bool _exc ;
SCARDCONTEXT _id ;
Scope _s ;
DWORD _state ;
} ;
//@}
}
//@}
# endif