/*! @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
# ifndef PCSC_LOG
//! Declare PCSC_LOG before #include in your code, if you want logging.
/*! PCSC_LOG passes its argument to a stream, so your definition must
behave so that the argument can be streamed .
Example , use std : : log :
@ code
# define PCSC_LOG(x) std::clog<<x<<" ("<<__PRETTY_FUNCTION__<<')'<<std::endl
# include <pcsc.hxx>
@ endcode
Example , use qDebug ( ) :
@ code
# define PCSC_LOG(x) qDebug()<<x
# include <pcsc.hxx>
@ endcode */
# define PCSC_LOG(x) // if unset, do nothing
# endif
# include <cryptaux.hxx>
# include <string>
# ifdef WIN32
# 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
# ifdef NO_CXX2011
# warning Old compiler (pre 2011): using boost as replacement for std
# include <boost/shared_ptr.hpp>
namespace std {
template < class T > class shared_ptr : public boost : : shared_ptr < T > {
public :
shared_ptr ( T * p ) : boost : : shared_ptr < T > ( p ) { }
} ;
}
# endif
# include <vector>
# include <map>
# include <memory>
namespace pcsc {
std : : string version ( ) ;
}
# 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 ) ;
- SCardReconnect ( hCard , SCARD_SHARE_SHARED ,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 ,
SCARD_LEAVE_CARD ,
& dwActiveProtocol ) ;
- 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 */
//! @see gpcsc
namespace pcsc {
//============================================================================
//! @addtogroup pcscexceptions
//@{
//----------------------------------------------------------------------------
class exception : public std : : exception {
public :
exception ( const std : : string & reason ) throw ( ) : _what ( " pcsc: " + reason ) { }
~ 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: \n " + reason ) {
}
} ;
//----------------------------------------------------------------------------
class access_error : public exception {
public :
access_error ( const std : : string & reason ) throw ( ) :
exception ( " smardcard access error: \n " + reason ) {
}
} ;
//----------------------------------------------------------------------------
class runtime_error : public exception {
public :
runtime_error ( const std : : string & reason , const std : : string & data ) throw ( ) :
exception ( " runtime error, \n " + reason + " : \n " + 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 ( Reader & r ) : _reader ( r ) , _running ( true ) {
_reader . beginTransaction ( ) ;
}
//! Cancels the transaction if not yet finished.
~ Transaction ( ) try {
end ( ) ;
} catch ( . . . ) {
if ( ! std : : uncaught_exception ( ) ) throw ;
}
//! Ends the running transaction.
void end ( ) {
if ( _running ) _reader . endTransaction ( ) ;
_running = false ;
}
private :
Reader & _reader ;
bool _running ;
} ;
//! State and attribute list of a reader.
class Status {
public :
Status ( unsigned long s , const std : : string & a ) : state ( s ) , atr ( a ) { }
const unsigned long state ;
const std : : string atr ;
} ;
//.............................................................methods
public :
//! Disconnects connection.
~ Reader ( ) {
_state = SCardDisconnect ( _id , SCARD_RESET_CARD ) ;
if ( ! std : : uncaught_exception ( ) )
_connection . check ( " disconnect smartcard " ) ;
}
//! Get reader status.
Status status ( ) {
DWORD dummy ( 0 ) ;
DWORD s ;
DWORD len ( MAX_ATR_SIZE ) ;
unsigned char a [ len ] ;
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 ) {
DWORD len ( 1024 ) ; // arbitrary
unsigned char buff [ len ] ;
SCARD_IO_REQUEST rPci ;
rPci . dwProtocol = pci ( ) - > dwProtocol ;
rPci . cbPciLength = sizeof ( rPci ) ;
// don't log; could log pins
//PCSC_LOG("SCardTransmit: "<<crypto::hex(in));
check ( SCardTransmit ( _id , & rPci ,
( unsigned char * ) in . c_str ( ) , in . size ( ) ,
0 , buff , & len ) ,
" smartcard transmit message " + crypto : : hex ( in ) ) ;
//PCSC_LOG(" -> "<<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 ( unsigned long controlCode ,
std : : string in ) {
DWORD len ( 256 ) ; // arbitrary
UCHAR dataBuffer [ 256 ] ;
PCSC_LOG ( " SCardControl: " < < " Command: " < < controlCode ) ;
PCSC_LOG ( " -> " < < crypto : : hex ( in ) ) ;
check ( SCardControl ( _id , controlCode ,
( unsigned char * ) in . c_str ( ) , in . size ( ) ,
dataBuffer , sizeof ( dataBuffer ) , & len ) ,
" smartcard control message sent " ) ;
PCSC_LOG ( " -> " < < 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 )
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 )
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 ( long state , const std : : string context = " " ) {
_state = state ;
return _connection . check ( state , context ) ;
}
//! Only Connection is allowed to instanciate.
friend class Connection ;
//! Establishes a connection to the given named cardreader
Reader ( const std : : string & nm , Connection & c ,
DWORD mode = SCARD_SHARE_SHARED ,
DWORD protocol = SCARD_PROTOCOL_T1 ) :
name ( nm ) , _connection ( c ) {
check ( SCardConnect ( _connection . _id , strconv ( name ) . c_str ( ) ,
mode , protocol ,
& _id , & _protocol ) ,
" connect smartcard \" " + name ) ;
}
//! forbidden
Reader ( ) ;
//! forbidden
Reader ( const Reader & ) ;
//...........................................................variables
private :
Connection & _connection ;
SCARDHANDLE _id ;
DWORD _state ;
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 :
//! 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 ) ,
_state ( SCardEstablishContext ( s , 0 , 0 , & _id ) ) {
check ( " establish smartcard context " ) ;
}
//! Closes the connection (releases the smartcard context)
~ Connection ( ) {
_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. */
Strings scan ( const Strings & groups = Strings ( ) ) {
Strings res ;
std : : string grp ( join ( groups ) ) ;
DWORD num ( 0 ) ;
if ( ! check ( SCardListReaders ( _id , groups . size ( ) ? strconv ( grp ) . data ( ) : 0 , 0 ,
& num ) ,
" smartcard get size of readers of groups " + grp ) )
return res ;
PCSC_LOG ( " size of readers: " < < num ) ;
if ( ! num ) return res ;
std : : auto_ptr < char_t > nm ( new char_t [ num ] ) ;
if ( ! check ( SCardListReaders ( _id , groups . size ( ) ? strconv ( grp ) . data ( ) : 0 ,
nm . get ( ) , & num ) ,
" smartcard list reader names of groups " + grp ) )
return res ;
PCSC_LOG ( " got all readers, size is " < < num ) ;
if ( ! num ) return res ;
PCSC_LOG ( " list of readers: "
< < crypto : : readable ( std : : string ( nm . get ( ) , num - 1 ) ) ) ;
return res = split ( strconv ( string ( nm . get ( ) , num - 1 ) ) ) ;
}
//! 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 . */
Reader & reader ( const std : : string & name ) {
if ( _reader . find ( name ) = = _reader . end ( ) )
_reader . insert
( std : : make_pair
( name , std : : shared_ptr < Reader > ( new Reader ( name , * this ) ) ) ) ;
return * _reader . find ( name ) - > second ;
}
//! Close connection of a named reader.
/*! If you access the same reader through raeder() later, the
connection will be reestablished . */
void close ( const std : : string & s ) {
}
//! @c false if last operation was not successful
operator bool ( ) const {
# ifdef WIN32
return ( _state > > 30 & 3 ) = = 0 ;
# else
return _state = = SCARD_S_SUCCESS ;
# endif
}
//! Get the describing text of the last error
std : : string error ( ) const {
std : : stringstream ss ;
switch ( _state ) {
case SCARD_E_CANCELLED :
ss < < " The action was canceled by an SCardCancel request. " ;
break ;
case SCARD_E_CANT_DISPOSE :
ss < < " The system could not dispose of the media in the requested "
< < " manner. " ;
break ;
case SCARD_E_CARD_UNSUPPORTED :
ss < < " The smart card does not meet minimal requirements for "
< < " support. " ;
break ;
case SCARD_E_DUPLICATE_READER :
ss < < " The reader driver did not produce a unique reader name. " ;
break ;
case SCARD_E_INSUFFICIENT_BUFFER :
ss < < " The data buffer for returned data is too small for the "
< < " returned data. " ;
break ;
case SCARD_E_INVALID_ATR :
ss < < " An ATR string obtained from the registry is not a valid "
< < " ATR string. " ;
break ;
case SCARD_E_INVALID_HANDLE :
ss < < " The supplied handle was not valid. " ;
break ;
case SCARD_E_INVALID_PARAMETER :
ss < < " One or more of the supplied parameters could not be properly "
< < " interpreted. " ;
break ;
case SCARD_E_INVALID_TARGET :
ss < < " Registry startup information is missing or not valid. " ;
break ;
case SCARD_E_INVALID_VALUE :
ss < < " One or more of the supplied parameters values could not "
< < " be properly interpreted. " ;
break ;
case SCARD_E_NOT_READY :
ss < < " The reader or smart card is not ready to accept commands. " ;
break ;
case SCARD_E_NOT_TRANSACTED :
ss < < " An attempt was made to end a nonexistent transaction. " ;
break ;
case SCARD_E_NO_MEMORY :
ss < < " Not enough memory available to complete this command. " ;
break ;
case SCARD_E_NO_SERVICE :
ss < < " The smart card resource manager is not running. " ;
break ;
case SCARD_E_NO_SMARTCARD :
ss < < " The operation requires a smart card, but no smart card "
< < " is currently in the device. " ;
break ;
case SCARD_E_PCI_TOO_SMALL :
ss < < " The PCI receive buffer was too small. " ;
break ;
case SCARD_E_PROTO_MISMATCH :
ss < < " The requested protocols are incompatible with the protocol "
< < " currently in use with the smart card. " ;
break ;
case SCARD_E_READER_UNAVAILABLE :
ss < < " The specified reader is not currently available for use. " ;
break ;
case SCARD_E_READER_UNSUPPORTED :
ss < < " The reader driver does not meet minimal requirements for "
< < " support. " ;
break ;
case SCARD_E_SERVICE_STOPPED :
ss < < " The smart card resource manager has shut down. " ;
break ;
case SCARD_E_SHARING_VIOLATION :
ss < < " The smart card cannot be accessed because of other outstanding "
< < " connections. " ;
break ;
case SCARD_E_SYSTEM_CANCELLED :
ss < < " The action was cancelled by the system, presumably to log "
< < " off or shut down. " ;
break ;
case SCARD_E_TIMEOUT :
ss < < " The user-specified time-out value has expired. " ;
break ;
case SCARD_E_UNKNOWN_CARD :
ss < < " The specified smart card name is not recognized. " ;
break ;
case SCARD_E_UNKNOWN_READER :
ss < < " The specified reader name is not recognized. " ;
break ;
case SCARD_E_UNSUPPORTED_FEATURE :
ss < < " This smart card does not support the requested feature. " ;
break ;
case SCARD_F_COMM_ERROR :
ss < < " An internal communications error has been detected. " ;
break ;
case SCARD_F_INTERNAL_ERROR :
ss < < " An internal consistency check failed. " ;
break ;
case SCARD_F_UNKNOWN_ERROR :
ss < < " An internal error has been detected, but the source is "
< < " unknown. " ;
break ;
case SCARD_F_WAITED_TOO_LONG :
ss < < " An internal consistency timer has expired. " ;
break ;
case SCARD_S_SUCCESS :
ss < < " No error was encountered. " ;
break ;
case SCARD_W_REMOVED_CARD :
ss < < " The smart card has been removed, so that further communication "
< < " is not possible. " ;
break ;
case SCARD_W_RESET_CARD :
ss < < " The smart card was reset. " ;
break ;
case SCARD_W_UNPOWERED_CARD :
ss < < " Power has been removed from the smart card, so that "
< < " further communication is not possible. " ;
break ;
case SCARD_W_UNRESPONSIVE_CARD :
ss < < " The smart card is not responding to a reset. " ;
break ;
case SCARD_W_UNSUPPORTED_CARD :
ss < < " The reader cannot communicate with the smart card, "
< < " due to ATR configuration conflicts. " ;
break ;
# ifndef __APPLE__
case SCARD_E_NO_READERS_AVAILABLE :
ss < < " No smart card reader is available. " ;
break ;
# endif
# ifdef WIN32
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 ;
case SCARD_E_BAD_SEEK :
ss < < " There was an error trying to set the smart card file "
< < " object pointer. " ;
break ;
case SCARD_E_CERTIFICATE_UNAVAILABLE :
ss < < " The requested certificate could not be obtained. " ;
break ;
case SCARD_E_COMM_DATA_LOST :
ss < < " A communications error with the smart card has been detected. " ;
break ;
case SCARD_E_DIR_NOT_FOUND :
ss < < " The specified directory does not exist in the smart card. " ;
break ;
case SCARD_E_FILE_NOT_FOUND :
ss < < " The specified file does not exist in the smart card. " ;
break ;
case SCARD_E_ICC_CREATEORDER :
ss < < " The requested order of object creation is not supported. " ;
break ;
case SCARD_E_ICC_INSTALLATION :
ss < < " No primary provider can be found for the smart card. " ;
break ;
case SCARD_E_INVALID_CHV :
ss < < " The supplied PIN is incorrect. " ;
break ;
case SCARD_E_NO_ACCESS :
ss < < " Access is denied to this file. " ;
break ;
case SCARD_E_NO_DIR :
ss < < " The supplied path does not represent a smart card directory. " ;
break ;
case SCARD_E_NO_FILE :
ss < < " The supplied path does not represent a smart card file. " ;
break ;
case SCARD_E_NO_KEY_CONTAINER :
ss < < " The requested key container does not exist on the smart card. " ;
break ;
case SCARD_E_NO_SUCH_CERTIFICATE :
ss < < " The requested certificate does not exist. " ;
break ;
case SCARD_E_SERVER_TOO_BUSY :
ss < < " The Smart card resource manager is too busy to complete this "
< < " operation. " ;
break ;
case SCARD_E_UNEXPECTED :
ss < < " An unexpected card error has occurred. " ;
break ;
case SCARD_E_UNKNOWN_RES_MNG :
ss < < " An unrecognized error code was returned from a layered "
< < " component. " ;
break ;
case SCARD_E_WRITE_TOO_MANY :
ss < < " The smartcard does not have enough memory to store the "
< < " information. " ;
break ;
case SCARD_P_SHUTDOWN :
ss < < " The operation has been aborted to allow the server application "
< < " to exit. " ;
break ;
case SCARD_W_CANCELLED_BY_USER :
ss < < " The action was cancelled by the user. " ;
break ;
case SCARD_W_CARD_NOT_AUTHENTICATED :
ss < < " No PIN was presented to the smart card. " ;
break ;
case SCARD_W_CHV_BLOCKED :
ss < < " The card cannot be accessed because the maximum number "
< < " of PIN entry attempts has been reached. " ;
break ;
case SCARD_W_EOF :
ss < < " The end of the smart card file has been reached. " ;
break ;
case SCARD_W_SECURITY_VIOLATION :
ss < < " Access was denied because of a security violation. " ;
break ;
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 ( ) ;
}
//................................................................methods
private :
//! 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 ( long state , const std : : string & context = " " ) {
_state = state ;
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 ( ) )
throw access_error ( context + " : " + error ( ) ) ;
else
throw access_error ( error ( ) ) ;
return * this ;
}
//! Splits a buffer with 0 separators into a vector of strings.
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.
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 ;
}
//..............................................................variables
private :
bool _exc ;
SCARDCONTEXT _id ;
long _state ;
std : : map < std : : string , std : : shared_ptr < Reader > > _reader ;
} ;
//@}
}
//@}
# endif