From d8bc9c49c2042cff5b79610bbce87ce863633c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Wed, 17 Jun 2009 12:30:45 +0000 Subject: [PATCH] imported pcsc.hxx --- doc/examples/pcsc-demo.cpp | 25 +++ src/pcsc.hxx | 405 +++++++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+) create mode 100644 doc/examples/pcsc-demo.cpp create mode 100644 src/pcsc.hxx diff --git a/doc/examples/pcsc-demo.cpp b/doc/examples/pcsc-demo.cpp new file mode 100644 index 0000000..e37c33c --- /dev/null +++ b/doc/examples/pcsc-demo.cpp @@ -0,0 +1,25 @@ +//g++ -I ../svn -I /usr/include/PCSC test.cpp -lpcsclite -ggdb3 +#include "pcscpp/pcsc.hxx" +#include "pcscpp/cardos.hxx" +#include + +int main(int, char const*const*const argv) try { + pcsc::Connection c; + pcsc::Connection::Strings reader(c.scan()); + std::cout<<"Suche PCSC-Reader ..."< +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +//! 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. */ +namespace pcsc { + + std::string hex(const std::string& data) { + std::stringstream res; + for (std::string::const_iterator it(data.begin()); it!=data.end(); ++it) + res<& attrs): + state(s), attr(attrs) { + } + Status(unsigned long s, const std::string& attrs): + state(s), attr(convert(attrs)) { + } + const unsigned long state; + const std::vector attr; + private: + static std::vector convert(const std::string& a) { + std::vector res; + for (std::string::const_iterator it(a.begin()); + it!=a.end(); ++it) + res.push_back(*it); + return res; + } + }; + + //.............................................................methods + public: + + //! Disconnects connection. + ~Reader() { + _state = SCardDisconnect(_id, SCARD_LEAVE_CARD); + if (!std::uncaught_exception()) _connection.check(); + } + + //! Get reader status. + Status status() { + unsigned long dummy(0); + unsigned long s; + unsigned long len(MAX_ATR_SIZE); + unsigned char a[len]; + check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len)); + return Status(s, std::string((char*)a, len)); + } + + //! Transmit data to reader. + std::string transmit(std::string in) { + unsigned long len(1024); // arbitrary + unsigned char buff[len]; + SCARD_IO_REQUEST rPci; + check(SCardTransmit(_id, pci(), + (unsigned char*)in.c_str(), in.size(), + &rPci, buff, &len)); + return std::string((char*)buff, len); + } + + //! @c false if last operation was not successful + operator bool() const { + return _state==SCARD_S_SUCCESS; + } + + //...........................................................variables + public: + + const std::string name; + + //.............................................................methods + private: + + //! Use scoped transactions with @ref Transaction + void beginTransaction() { + check(SCardBeginTransaction(_id)); + } + + //! Use scoped transactions with @ref Transaction + void commitTransaction() { + check(SCardEndTransaction(_id, SCARD_LEAVE_CARD)); + } + + //! Use scoped transactions with @ref Transaction + void cancelTransaction() { + check(SCardCancelTransaction(_id)); + } + + /*! @throw not_implemented if _protocol is unknown. */ + 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) { + _state = state; + return _connection.check(state); + } + + //! Only Connection is allowed to instanciate. + friend class Connection; + + //! Establishes a connection to the given named cardreader + Reader(const std::string& nm, Connection& c): + name(nm), _connection(c) { + check(SCardConnect(_connection._id, name.c_str(), + SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, + &_id, &_protocol)); + } + + //! forbidden + Reader(); + + //! forbidden + Reader(const Reader&); + + //...........................................................variables + private: + + Connection& _connection; + long _id; + long _state; + unsigned long _protocol; + + }; + //------------------------------------------------------------------Reader + + enum Scope { + USER = SCARD_SCOPE_USER, + TERMINAL = SCARD_SCOPE_TERMINAL, + SYSTEM = SCARD_SCOPE_SYSTEM + }; + + typedef std::vector 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: "< nm(new char[num]); + if (!check(SCardListReaders(_id, grp.size()?grp.data():0, + nm.get(), &num))) + return res; + return res = split(std::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, 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 { + return _state==SCARD_S_SUCCESS; + } + + //! Get the describing text of the last error + std::string error() const { + return pcsc_stringify_error(_state); + } + + //................................................................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) { + _state = state; + return check(); + } + + //! Throws an exception if neccessary. + /*! @throw access_error if it is instanciated for exceptions and + an error occured in the last command. */ + bool check() { + if (_exc&&_state!=SCARD_S_SUCCESS) throw access_error(error()); + return _state==SCARD_S_SUCCESS; + } + + //! 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); possize()+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; + for (Strings::const_iterator it(in.begin()); + it!=in.end(); ++it) + res+=*it+'\0'; + return res; + } + + //..............................................................variables + private: + + bool _exc; + long _id; + long _state; + std::map > _reader; + + }; + +} +#endif