imported pcsc.hxx
This commit is contained in:
		
							
								
								
									
										25
									
								
								doc/examples/pcsc-demo.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								doc/examples/pcsc-demo.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | //g++ -I ../svn -I /usr/include/PCSC test.cpp -lpcsclite -ggdb3 | ||||||
|  | #include "pcscpp/pcsc.hxx" | ||||||
|  | #include "pcscpp/cardos.hxx" | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  | int main(int, char const*const*const argv) try { | ||||||
|  |   pcsc::Connection c; | ||||||
|  |   pcsc::Connection::Strings reader(c.scan()); | ||||||
|  |   std::cout<<"Suche PCSC-Reader ..."<<std::endl; | ||||||
|  |   if (!reader.size()) std::cout<<"Keine gefunden."<<std::endl; | ||||||
|  |   for (pcsc::Connection::Strings::const_iterator it(reader.begin()); | ||||||
|  |        it!=reader.end(); ++it) { | ||||||
|  |     std::cout<<"Reader: "<<*it<<std::endl; | ||||||
|  |     pcsc::Connection::Reader::Status s(c.reader(*it).status()); | ||||||
|  |     std::cout<<"Status = "<<s.state<<std::endl; | ||||||
|  |     std::cout<<"Attribute = "; | ||||||
|  |     for (std::vector<unsigned char>::const_iterator it(s.attr.begin()); | ||||||
|  |          it!=s.attr.end(); ++it) | ||||||
|  |       std::cout<<std::hex<<(int)*it<<" "; | ||||||
|  |     std::cout<<std::endl; | ||||||
|  |   } | ||||||
|  |   return 0; | ||||||
|  |  } catch (std::exception& x) { | ||||||
|  |   std::cerr<<"**** FEHLER in "<<*argv<<": "<<x.what()<<std::endl; | ||||||
|  |  } | ||||||
							
								
								
									
										405
									
								
								src/pcsc.hxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								src/pcsc.hxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,405 @@ | |||||||
|  | /*! @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 <PCSC/wintypes.h> | ||||||
|  | #include <PCSC/pcsclite.h> | ||||||
|  | #include <PCSC/winscard.h> | ||||||
|  |  | ||||||
|  | #include <boost/shared_ptr.hpp> | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include <map> | ||||||
|  | #include <memory> | ||||||
|  |  | ||||||
|  | #include <sstream> | ||||||
|  | #include <iomanip> | ||||||
|  |  | ||||||
|  | //! 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<<std::hex<<std::setfill('0')<<std::setw(2)<<(int)*it; | ||||||
|  |     return res.str(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //============================================================================ | ||||||
|  |   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: exception { | ||||||
|  |     public: | ||||||
|  |       not_implemented(const std::string& reason) throw(): | ||||||
|  |           exception("feature is not implemented:\n"+reason) { | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|  |   class access_error: exception { | ||||||
|  |     public: | ||||||
|  |       access_error(const std::string& reason) throw(): | ||||||
|  |           exception("smardcard access error:\n"+reason) { | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   //============================================================================ | ||||||
|  |   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 cancelled | ||||||
|  |               in the destructor, unless it is committed before. That | ||||||
|  |               means: If you commit the transaction, it is executed. If | ||||||
|  |               you leave the code block unexpectedly, i.e. through an | ||||||
|  |               exception, the transaction is cancelled. | ||||||
|  |  | ||||||
|  |               @code | ||||||
|  |               pcsc::Connection c; | ||||||
|  |               { | ||||||
|  |               Transaction t(c.reader("name")); | ||||||
|  |               [...] // do some stuff, possible exceptions thrown | ||||||
|  |               if (problem) return; // automatically cancelled | ||||||
|  |               [...] | ||||||
|  |               t.commit(); // commit if we reach this line | ||||||
|  |               } // cancelled, 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 { | ||||||
|  |                 if (_running) cancel(); | ||||||
|  |               } catch (...) { | ||||||
|  |                 if (!std::uncaught_exception()) throw; | ||||||
|  |               } | ||||||
|  |               //! Ends (commits) the running transaction. | ||||||
|  |               void commit() { | ||||||
|  |                 if (_running) _reader.commitTransaction(); | ||||||
|  |                 _running = false; | ||||||
|  |               } | ||||||
|  |               //! Cancels the running transaction. | ||||||
|  |               void cancel() { | ||||||
|  |                 if (_running) _reader.cancelTransaction(); | ||||||
|  |                 _running = false; | ||||||
|  |               } | ||||||
|  |             private: | ||||||
|  |               Reader& _reader; | ||||||
|  |               bool _running; | ||||||
|  |           }; | ||||||
|  |  | ||||||
|  |           //! State and attribute list of a reader. | ||||||
|  |           class Status { | ||||||
|  |             public: | ||||||
|  |               Status(unsigned long s, const std::vector<unsigned char>& 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<unsigned char> attr; | ||||||
|  |             private: | ||||||
|  |               static std::vector<unsigned char> convert(const std::string& a) { | ||||||
|  |                 std::vector<unsigned char> 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<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=SYSTEM, bool exceptions=true): | ||||||
|  |           _exc(exceptions), _id(0), | ||||||
|  |           _state(SCardEstablishContext(s, 0, 0, &_id)) { | ||||||
|  |         check(); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       //! Closes the connection (releases the smartcard context) | ||||||
|  |       ~Connection() { | ||||||
|  |         _state = SCardReleaseContext(_id); | ||||||
|  |         if (!std::uncaught_exception()) check(); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       //! 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)); | ||||||
|  |         unsigned long num(0); | ||||||
|  |         if (!check(SCardListReaders(_id, grp.size()?grp.data():0, 0, &num))) | ||||||
|  |           return res; | ||||||
|  |         std::auto_ptr<char> 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); pos<in.size(); | ||||||
|  |              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; | ||||||
|  |         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<std::string, boost::shared_ptr<Reader> > _reader; | ||||||
|  |  | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | #endif | ||||||
		Reference in New Issue
	
	Block a user