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