#[macro_use]
extern crate bitflags;
extern crate pcsc_sys as ffi;
use std::ffi::{CStr, CString};
use std::mem::{forget, transmute};
use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr::{null, null_mut};
use std::sync::Arc;
use ffi::{DWORD, LONG};
const DUMMY_LONG: LONG = -1;
const DUMMY_DWORD: DWORD = 0xdead_beef;
bitflags! {
    
    pub struct State: DWORD {
        const UNAWARE = ffi::SCARD_STATE_UNAWARE;
        const IGNORE = ffi::SCARD_STATE_IGNORE;
        const CHANGED = ffi::SCARD_STATE_CHANGED;
        const UNKNOWN = ffi::SCARD_STATE_UNKNOWN;
        const UNAVAILABLE = ffi::SCARD_STATE_UNAVAILABLE;
        const EMPTY = ffi::SCARD_STATE_EMPTY;
        const PRESENT = ffi::SCARD_STATE_PRESENT;
        const ATRMATCH = ffi::SCARD_STATE_ATRMATCH;
        const EXCLUSIVE = ffi::SCARD_STATE_EXCLUSIVE;
        const INUSE = ffi::SCARD_STATE_INUSE;
        const MUTE = ffi::SCARD_STATE_MUTE;
        const UNPOWERED = ffi::SCARD_STATE_UNPOWERED;
    }
}
bitflags! {
    
    pub struct Status: DWORD {
        const UNKNOWN = ffi::SCARD_UNKNOWN;
        const ABSENT = ffi::SCARD_ABSENT;
        const PRESENT = ffi::SCARD_PRESENT;
        const SWALLOWED = ffi::SCARD_SWALLOWED;
        const POWERED = ffi::SCARD_POWERED;
        const NEGOTIABLE = ffi::SCARD_NEGOTIABLE;
        const SPECIFIC = ffi::SCARD_SPECIFIC;
    }
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ShareMode {
    Exclusive = ffi::SCARD_SHARE_EXCLUSIVE as u32,
    Shared = ffi::SCARD_SHARE_SHARED as u32,
    Direct = ffi::SCARD_SHARE_DIRECT as u32,
}
impl ShareMode {
    fn into_raw(self) -> DWORD {
        DWORD::from(self as u32)
    }
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Protocol {
    T0 = ffi::SCARD_PROTOCOL_T0 as u32,
    T1 = ffi::SCARD_PROTOCOL_T1 as u32,
    RAW = ffi::SCARD_PROTOCOL_RAW as u32,
}
impl Protocol {
    fn from_raw(raw: DWORD) -> Protocol {
        match raw {
            ffi::SCARD_PROTOCOL_T0 => Protocol::T0,
            ffi::SCARD_PROTOCOL_T1 => Protocol::T1,
            ffi::SCARD_PROTOCOL_RAW => Protocol::RAW,
            
            
            _ => panic!("impossible protocol: {:#x}", raw),
        }
    }
}
bitflags! {
    
    pub struct Protocols: DWORD {
        const UNDEFINED = ffi::SCARD_PROTOCOL_UNDEFINED;
        const T0 = ffi::SCARD_PROTOCOL_T0;
        const T1 = ffi::SCARD_PROTOCOL_T1;
        const RAW = ffi::SCARD_PROTOCOL_RAW;
        const ANY = ffi::SCARD_PROTOCOL_ANY;
    }
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Disposition {
    LeaveCard = ffi::SCARD_LEAVE_CARD as u32,
    ResetCard = ffi::SCARD_RESET_CARD as u32,
    UnpowerCard = ffi::SCARD_UNPOWER_CARD as u32,
    EjectCard = ffi::SCARD_EJECT_CARD as u32,
}
impl Disposition {
    fn into_raw(self) -> DWORD {
        DWORD::from(self as u32)
    }
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Error {
    
    InternalError = ffi::SCARD_F_INTERNAL_ERROR as u32,
    Cancelled = ffi::SCARD_E_CANCELLED as u32,
    InvalidHandle = ffi::SCARD_E_INVALID_HANDLE as u32,
    InvalidParameter = ffi::SCARD_E_INVALID_PARAMETER as u32,
    InvalidTarget = ffi::SCARD_E_INVALID_TARGET as u32,
    NoMemory = ffi::SCARD_E_NO_MEMORY as u32,
    WaitedTooLong = ffi::SCARD_F_WAITED_TOO_LONG as u32,
    InsufficientBuffer = ffi::SCARD_E_INSUFFICIENT_BUFFER as u32,
    UnknownReader = ffi::SCARD_E_UNKNOWN_READER as u32,
    Timeout = ffi::SCARD_E_TIMEOUT as u32,
    SharingViolation = ffi::SCARD_E_SHARING_VIOLATION as u32,
    NoSmartcard = ffi::SCARD_E_NO_SMARTCARD as u32,
    UnknownCard = ffi::SCARD_E_UNKNOWN_CARD as u32,
    CantDispose = ffi::SCARD_E_CANT_DISPOSE as u32,
    ProtoMismatch = ffi::SCARD_E_PROTO_MISMATCH as u32,
    NotReady = ffi::SCARD_E_NOT_READY as u32,
    InvalidValue = ffi::SCARD_E_INVALID_VALUE as u32,
    SystemCancelled = ffi::SCARD_E_SYSTEM_CANCELLED as u32,
    CommError = ffi::SCARD_F_COMM_ERROR as u32,
    UnknownError = ffi::SCARD_F_UNKNOWN_ERROR as u32,
    InvalidAtr = ffi::SCARD_E_INVALID_ATR as u32,
    NotTransacted = ffi::SCARD_E_NOT_TRANSACTED as u32,
    ReaderUnavailable = ffi::SCARD_E_READER_UNAVAILABLE as u32,
    Shutdown = ffi::SCARD_P_SHUTDOWN as u32,
    PciTooSmall = ffi::SCARD_E_PCI_TOO_SMALL as u32,
    ReaderUnsupported = ffi::SCARD_E_READER_UNSUPPORTED as u32,
    DuplicateReader = ffi::SCARD_E_DUPLICATE_READER as u32,
    CardUnsupported = ffi::SCARD_E_CARD_UNSUPPORTED as u32,
    NoService = ffi::SCARD_E_NO_SERVICE as u32,
    ServiceStopped = ffi::SCARD_E_SERVICE_STOPPED as u32,
    #[cfg(target_os = "windows")]
    Unexpected = ffi::SCARD_E_UNEXPECTED as u32,
    IccInstallation = ffi::SCARD_E_ICC_INSTALLATION as u32,
    IccCreateorder = ffi::SCARD_E_ICC_CREATEORDER as u32,
    UnsupportedFeature = ffi::SCARD_E_UNSUPPORTED_FEATURE as u32,
    DirNotFound = ffi::SCARD_E_DIR_NOT_FOUND as u32,
    FileNotFound = ffi::SCARD_E_FILE_NOT_FOUND as u32,
    NoDir = ffi::SCARD_E_NO_DIR as u32,
    NoFile = ffi::SCARD_E_NO_FILE as u32,
    NoAccess = ffi::SCARD_E_NO_ACCESS as u32,
    WriteTooMany = ffi::SCARD_E_WRITE_TOO_MANY as u32,
    BadSeek = ffi::SCARD_E_BAD_SEEK as u32,
    InvalidChv = ffi::SCARD_E_INVALID_CHV as u32,
    UnknownResMng = ffi::SCARD_E_UNKNOWN_RES_MNG as u32,
    NoSuchCertificate = ffi::SCARD_E_NO_SUCH_CERTIFICATE as u32,
    CertificateUnavailable = ffi::SCARD_E_CERTIFICATE_UNAVAILABLE as u32,
    NoReadersAvailable = ffi::SCARD_E_NO_READERS_AVAILABLE as u32,
    CommDataLost = ffi::SCARD_E_COMM_DATA_LOST as u32,
    NoKeyContainer = ffi::SCARD_E_NO_KEY_CONTAINER as u32,
    ServerTooBusy = ffi::SCARD_E_SERVER_TOO_BUSY as u32,
    
    
    UnsupportedCard = ffi::SCARD_W_UNSUPPORTED_CARD as u32,
    UnresponsiveCard = ffi::SCARD_W_UNRESPONSIVE_CARD as u32,
    UnpoweredCard = ffi::SCARD_W_UNPOWERED_CARD as u32,
    ResetCard = ffi::SCARD_W_RESET_CARD as u32,
    RemovedCard = ffi::SCARD_W_REMOVED_CARD as u32,
    SecurityViolation = ffi::SCARD_W_SECURITY_VIOLATION as u32,
    WrongChv = ffi::SCARD_W_WRONG_CHV as u32,
    ChvBlocked = ffi::SCARD_W_CHV_BLOCKED as u32,
    Eof = ffi::SCARD_W_EOF as u32,
    CancelledByUser = ffi::SCARD_W_CANCELLED_BY_USER as u32,
    CardNotAuthenticated = ffi::SCARD_W_CARD_NOT_AUTHENTICATED as u32,
    CacheItemNotFound = ffi::SCARD_W_CACHE_ITEM_NOT_FOUND as u32,
    CacheItemStale = ffi::SCARD_W_CACHE_ITEM_STALE as u32,
    CacheItemTooBig = ffi::SCARD_W_CACHE_ITEM_TOO_BIG as u32,
    
}
impl Error {
    fn from_raw(raw: LONG) -> Error {
        unsafe {
            
            if ffi::SCARD_F_INTERNAL_ERROR <= raw && raw <= ffi::SCARD_E_SERVER_TOO_BUSY
                || ffi::SCARD_W_UNSUPPORTED_CARD <= raw && raw <= ffi::SCARD_W_CACHE_ITEM_TOO_BIG
            {
                transmute::<u32, Error>(raw as u32)
            } else {
                if cfg!(debug_assertions) {
                    panic!("unknown PCSC error code: {:#x}", raw);
                }
                
                
                Error::UnknownError
            }
        }
    }
    fn into_raw(self) -> LONG {
        LONG::from(self as u32 as i32)
    }
}
impl std::error::Error for Error {
    fn description(&self) -> &str {
        
        match *self {
            Error::InternalError => "An internal consistency check failed",
            Error::Cancelled => "The action was cancelled by an SCardCancel request",
            Error::InvalidHandle => "The supplied handle was invalid",
            Error::InvalidParameter => "One or more of the supplied parameters could not be properly interpreted",
            Error::InvalidTarget => "Registry startup information is missing or invalid",
            Error::NoMemory => "Not enough memory available to complete this command",
            Error::WaitedTooLong => "An internal consistency timer has expired",
            Error::InsufficientBuffer => "The data buffer to receive returned data is too small for the returned data",
            Error::UnknownReader => "The specified reader name is not recognized",
            Error::Timeout => "The user-specified timeout value has expired",
            Error::SharingViolation => "The smart card cannot be accessed because of other connections outstanding",
            Error::NoSmartcard => "The operation requires a Smart Card, but no Smart Card is currently in the device",
            Error::UnknownCard => "The specified smart card name is not recognized",
            Error::CantDispose => "The system could not dispose of the media in the requested manner",
            Error::ProtoMismatch => "The requested protocols are incompatible with the protocol currently in use with the smart card",
            Error::NotReady => "The reader or smart card is not ready to accept commands",
            Error::InvalidValue => "One or more of the supplied parameters values could not be properly interpreted",
            Error::SystemCancelled => "The action was cancelled by the system, presumably to log off or shut down",
            Error::CommError => "An internal communications error has been detected",
            Error::UnknownError => "An internal error has been detected, but the source is unknown",
            Error::InvalidAtr => "An ATR obtained from the registry is not a valid ATR string",
            Error::NotTransacted => "An attempt was made to end a non-existent transaction",
            Error::ReaderUnavailable => "The specified reader is not currently available for use",
            Error::Shutdown => "The operation has been aborted to allow the server application to exit",
            Error::PciTooSmall => "The PCI Receive buffer was too small",
            Error::ReaderUnsupported => "The reader driver does not meet minimal requirements for support",
            Error::DuplicateReader => "The reader driver did not produce a unique reader name",
            Error::CardUnsupported => "The smart card does not meet minimal requirements for support",
            Error::NoService => "The Smart card resource manager is not running",
            Error::ServiceStopped => "The Smart card resource manager has shut down",
            #[cfg(target_os = "windows")]
            Error::Unexpected => "An unexpected card error has occurred",
            Error::UnsupportedFeature => "This smart card does not support the requested feature",
            Error::IccInstallation => "No primary provider can be found for the smart card",
            Error::IccCreateorder => "The requested order of object creation is not supported",
            Error::DirNotFound => "The identified directory does not exist in the smart card",
            Error::FileNotFound => "The identified file does not exist in the smart card",
            Error::NoDir => "The supplied path does not represent a smart card directory",
            Error::NoFile => "The supplied path does not represent a smart card file",
            Error::NoAccess => "Access is denied to this file",
            Error::WriteTooMany => "The smart card does not have enough memory to store the information",
            Error::BadSeek => "There was an error trying to set the smart card file object pointer",
            Error::InvalidChv => "The supplied PIN is incorrect",
            Error::UnknownResMng => "An unrecognized error code was returned from a layered component",
            Error::NoSuchCertificate => "The requested certificate does not exist",
            Error::CertificateUnavailable => "The requested certificate could not be obtained",
            Error::NoReadersAvailable => "Cannot find a smart card reader",
            Error::CommDataLost => "A communications error with the smart card has been detected. Retry the operation",
            Error::NoKeyContainer => "The requested key container does not exist on the smart card",
            Error::ServerTooBusy => "The smart card resource manager is too busy to complete this operation",
            Error::UnsupportedCard => "The reader cannot communicate with the card, due to ATR string configuration conflicts",
            Error::UnresponsiveCard => "The smart card is not responding to a reset",
            Error::UnpoweredCard => "Power has been removed from the smart card, so that further communication is not possible",
            Error::ResetCard => "The smart card has been reset, so any shared state information is invalid",
            Error::RemovedCard => "The smart card has been removed, so further communication is not possible",
            Error::SecurityViolation => "Access was denied because of a security violation",
            Error::WrongChv => "The card cannot be accessed because the wrong PIN was presented",
            Error::ChvBlocked => "The card cannot be accessed because the maximum number of PIN entry attempts has been reached",
            Error::Eof => "The end of the smart card file has been reached",
            Error::CancelledByUser => r#"The user pressed "Cancel" on a Smart Card Selection Dialog"#,
            Error::CardNotAuthenticated => "No PIN was presented to the smart card",
            Error::CacheItemNotFound => "The requested item could not be found in the cache",
            Error::CacheItemStale => "The requested cache item is too old and was deleted from the cache",
            Error::CacheItemTooBig => "The new cache item exceeds the maximum per-item size defined for the cache",
        }
    }
}
impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(std::error::Error::description(self))
    }
}
macro_rules! try_pcsc {
    ($e:expr) => (match $e {
        ffi::SCARD_S_SUCCESS => (),
        err => return Err(Error::from_raw(err)),
    });
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Scope {
    User = ffi::SCARD_SCOPE_USER as u32,
    Terminal = ffi::SCARD_SCOPE_TERMINAL as u32,
    System = ffi::SCARD_SCOPE_SYSTEM as u32,
    Global = ffi::SCARD_SCOPE_GLOBAL as u32,
}
impl Scope {
    fn into_raw(self) -> DWORD {
        DWORD::from(self as u32)
    }
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AttributeClass {
    VendorInfo = ffi::SCARD_CLASS_VENDOR_INFO as u32,
    Communications = ffi::SCARD_CLASS_COMMUNICATIONS as u32,
    Protocol = ffi::SCARD_CLASS_PROTOCOL as u32,
    PowerMgmt = ffi::SCARD_CLASS_POWER_MGMT as u32,
    Security = ffi::SCARD_CLASS_SECURITY as u32,
    Mechanical = ffi::SCARD_CLASS_MECHANICAL as u32,
    VendorDefined = ffi::SCARD_CLASS_VENDOR_DEFINED as u32,
    IfdProtocol = ffi::SCARD_CLASS_IFD_PROTOCOL as u32,
    IccState = ffi::SCARD_CLASS_ICC_STATE as u32,
    System = ffi::SCARD_CLASS_SYSTEM as u32,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Attribute {
    VendorName = ffi::SCARD_ATTR_VENDOR_NAME as u32,
    VendorIfdType = ffi::SCARD_ATTR_VENDOR_IFD_TYPE as u32,
    VendorIfdVersion = ffi::SCARD_ATTR_VENDOR_IFD_VERSION as u32,
    VendorIfdSerialNo = ffi::SCARD_ATTR_VENDOR_IFD_SERIAL_NO as u32,
    ChannelId = ffi::SCARD_ATTR_CHANNEL_ID as u32,
    AsyncProtocolTypes = ffi::SCARD_ATTR_ASYNC_PROTOCOL_TYPES as u32,
    DefaultClk = ffi::SCARD_ATTR_DEFAULT_CLK as u32,
    MaxClk = ffi::SCARD_ATTR_MAX_CLK as u32,
    DefaultDataRate = ffi::SCARD_ATTR_DEFAULT_DATA_RATE as u32,
    MaxDataRate = ffi::SCARD_ATTR_MAX_DATA_RATE as u32,
    MaxIfsd = ffi::SCARD_ATTR_MAX_IFSD as u32,
    SyncProtocolTypes = ffi::SCARD_ATTR_SYNC_PROTOCOL_TYPES as u32,
    PowerMgmtSupport = ffi::SCARD_ATTR_POWER_MGMT_SUPPORT as u32,
    UserToCardAuthDevice = ffi::SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE as u32,
    UserAuthInputDevice = ffi::SCARD_ATTR_USER_AUTH_INPUT_DEVICE as u32,
    Characteristics = ffi::SCARD_ATTR_CHARACTERISTICS as u32,
    CurrentProtocolType = ffi::SCARD_ATTR_CURRENT_PROTOCOL_TYPE as u32,
    CurrentClk = ffi::SCARD_ATTR_CURRENT_CLK as u32,
    CurrentF = ffi::SCARD_ATTR_CURRENT_F as u32,
    CurrentD = ffi::SCARD_ATTR_CURRENT_D as u32,
    CurrentN = ffi::SCARD_ATTR_CURRENT_N as u32,
    CurrentW = ffi::SCARD_ATTR_CURRENT_W as u32,
    CurrentIfsc = ffi::SCARD_ATTR_CURRENT_IFSC as u32,
    CurrentIfsd = ffi::SCARD_ATTR_CURRENT_IFSD as u32,
    CurrentBwt = ffi::SCARD_ATTR_CURRENT_BWT as u32,
    CurrentCwt = ffi::SCARD_ATTR_CURRENT_CWT as u32,
    CurrentEbcEncoding = ffi::SCARD_ATTR_CURRENT_EBC_ENCODING as u32,
    ExtendedBwt = ffi::SCARD_ATTR_EXTENDED_BWT as u32,
    IccPresence = ffi::SCARD_ATTR_ICC_PRESENCE as u32,
    IccInterfaceStatus = ffi::SCARD_ATTR_ICC_INTERFACE_STATUS as u32,
    CurrentIoState = ffi::SCARD_ATTR_CURRENT_IO_STATE as u32,
    AtrString = ffi::SCARD_ATTR_ATR_STRING as u32,
    IccTypePerAtr = ffi::SCARD_ATTR_ICC_TYPE_PER_ATR as u32,
    EscReset = ffi::SCARD_ATTR_ESC_RESET as u32,
    EscCancel = ffi::SCARD_ATTR_ESC_CANCEL as u32,
    EscAuthrequest = ffi::SCARD_ATTR_ESC_AUTHREQUEST as u32,
    Maxinput = ffi::SCARD_ATTR_MAXINPUT as u32,
    DeviceUnit = ffi::SCARD_ATTR_DEVICE_UNIT as u32,
    DeviceInUse = ffi::SCARD_ATTR_DEVICE_IN_USE as u32,
    DeviceFriendlyName = ffi::SCARD_ATTR_DEVICE_FRIENDLY_NAME as u32,
    DeviceSystemName = ffi::SCARD_ATTR_DEVICE_SYSTEM_NAME as u32,
    SupressT1IfsRequest = ffi::SCARD_ATTR_SUPRESS_T1_IFS_REQUEST as u32,
}
impl Attribute {
    fn into_raw(self) -> DWORD {
        DWORD::from(self as u32)
    }
}
pub const MAX_ATR_SIZE: usize = ffi::MAX_ATR_SIZE;
pub const MAX_BUFFER_SIZE: usize = ffi::MAX_BUFFER_SIZE;
pub const MAX_BUFFER_SIZE_EXTENDED: usize = ffi::MAX_BUFFER_SIZE_EXTENDED;
#[allow(non_snake_case)]
pub fn PNP_NOTIFICATION() -> &'static CStr {
    
    CStr::from_bytes_with_nul(b"\\\\?PnP?\\Notification\0").unwrap()
}
pub fn ctl_code(code: DWORD) -> DWORD {
    ffi::SCARD_CTL_CODE(code)
}
#[repr(C)]
pub struct ReaderState {
    
    inner: ffi::SCARD_READERSTATE,
}
fn get_protocol_pci(protocol: Protocol) -> &'static ffi::SCARD_IO_REQUEST {
    unsafe {
        match protocol {
            Protocol::T0 => &ffi::g_rgSCardT0Pci,
            Protocol::T1 => &ffi::g_rgSCardT1Pci,
            Protocol::RAW => &ffi::g_rgSCardRawPci,
        }
    }
}
struct ContextInner {
    handle: ffi::SCARDCONTEXT,
}
pub struct Context {
    inner: Arc<ContextInner>,
}
pub struct Card {
    
    _context: Context,
    handle: ffi::SCARDHANDLE,
    active_protocol: Protocol,
}
pub struct Transaction<'tx> {
    card: &'tx mut Card,
}
#[derive(Clone)]
pub struct ReaderNames<'buf> {
    buf: &'buf [u8],
    pos: usize,
}
impl<'buf> Iterator for ReaderNames<'buf> {
    type Item = &'buf CStr;
    fn next(&mut self) -> Option<&'buf CStr> {
        match self.buf[self.pos..].iter().position(|&c| c == 0) {
            None | Some(0) => None,
            Some(len) => {
                let old_pos = self.pos;
                self.pos += len + 1;
                
                Some(CStr::from_bytes_with_nul(&self.buf[old_pos..self.pos]).unwrap())
            }
        }
    }
}
impl Context {
    
    
    
    
    
    
    
    pub fn establish(
        scope: Scope,
    ) -> Result<Context, Error> {
        unsafe {
            let mut handle: ffi::SCARDCONTEXT = DUMMY_LONG as ffi::SCARDCONTEXT;
            try_pcsc!(ffi::SCardEstablishContext(
                scope.into_raw(),
                null(),
                null(),
                &mut handle,
            ));
            Ok(Context {
                inner: Arc::new(ContextInner {
                    handle,
                }),
            })
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn release(
        self
    ) -> Result<(), (Context, Error)> {
        match Arc::try_unwrap(self.inner) {
            Ok(inner) => {
                unsafe {
                    let err = ffi::SCardReleaseContext(
                        inner.handle,
                    );
                    if err != ffi::SCARD_S_SUCCESS {
                        let context = Context { inner: Arc::new(inner) };
                        return Err((context, Error::from_raw(err)));
                    }
                    
                    forget(inner);
                    Ok(())
                }
            },
            Err(arc_inner) => {
                let context = Context { inner: arc_inner };
                Err((context, Error::CantDispose))
            }
        }
    }
    
    
    
    
    
    
    
    pub fn is_valid(
        &self
    ) -> Result<(), Error> {
        unsafe {
            try_pcsc!(ffi::SCardIsValidContext(
                self.inner.handle,
            ));
            Ok(())
        }
    }
    
    
    
    
    
    
    
    
    pub fn cancel(
        &self,
    ) -> Result<(), Error> {
        unsafe {
            try_pcsc!(ffi::SCardCancel(
                self.inner.handle,
            ));
            Ok(())
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn list_readers<'buf>(
        &self,
        buffer: &'buf mut [u8],
    ) -> Result<ReaderNames<'buf>, Error> {
        unsafe {
            assert!(buffer.len() <= std::u32::MAX as usize);
            let mut buflen = buffer.len() as DWORD;
            let err = ffi::SCardListReaders(
                self.inner.handle,
                null(),
                buffer.as_mut_ptr() as *mut c_char,
                &mut buflen,
            );
            if err == Error::NoReadersAvailable.into_raw() {
                return Ok(ReaderNames {
                    buf: b"\0",
                    pos: 0,
                });
            }
            if err != ffi::SCARD_S_SUCCESS {
                return Err(Error::from_raw(err));
            }
            Ok(ReaderNames {
                buf: &buffer[..buflen as usize],
                pos: 0,
            })
        }
    }
    
    
    
    
    
    
    pub fn list_readers_len(
        &self,
    ) -> Result<usize, Error> {
        unsafe {
            let mut buflen = DUMMY_DWORD;
            let err = ffi::SCardListReaders(
                self.inner.handle,
                null(),
                null_mut(),
                &mut buflen,
            );
            if err == Error::NoReadersAvailable.into_raw() {
                return Ok(0);
            }
            if err != ffi::SCARD_S_SUCCESS {
                return Err(Error::from_raw(err));
            }
            Ok(buflen as usize)
        }
    }
    
    
    
    
    
    
    
    
    pub fn connect(
        &self,
        reader: &CStr,
        share_mode: ShareMode,
        preferred_protocols: Protocols,
    ) -> Result<Card, Error> {
        unsafe {
            let mut handle: ffi::SCARDHANDLE = DUMMY_LONG as ffi::SCARDHANDLE;
            let mut raw_active_protocol: DWORD = DUMMY_DWORD;
            try_pcsc!(ffi::SCardConnect(
                self.inner.handle,
                reader.as_ptr(),
                share_mode.into_raw(),
                preferred_protocols.bits(),
                &mut handle,
                &mut raw_active_protocol,
            ));
            let active_protocol = Protocol::from_raw(raw_active_protocol);
            Ok(Card {
                _context: self.clone(),
                handle,
                active_protocol,
            })
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn get_status_change<D>(
        &self,
        timeout: D,
        readers: &mut [ReaderState],
    ) -> Result<(), Error>
        where D: Into<Option<std::time::Duration>> {
        let timeout_ms = match timeout.into() {
            Some(duration) => {
                let timeout_ms_u64 = duration.as_secs()
                    .saturating_mul(1000)
                    .saturating_add(u64::from(duration.subsec_nanos()) / 1_000_000);
                std::cmp::min(ffi::INFINITE, timeout_ms_u64 as DWORD)
            },
            None => ffi::INFINITE
        };
        unsafe {
            assert!(readers.len() <= std::u32::MAX as usize);
            try_pcsc!(ffi::SCardGetStatusChange(
                self.inner.handle,
                timeout_ms,
                readers.as_mut_ptr() as *mut ffi::SCARD_READERSTATE,
                readers.len() as DWORD,
            ));
            Ok(())
        }
    }
}
impl Drop for ContextInner {
    fn drop(&mut self) {
        unsafe {
            
            
            let _err = ffi::SCardReleaseContext(
                self.handle,
            );
        }
    }
}
impl Clone for Context {
    
    
    
    
    
    fn clone(&self) -> Self {
        Context {
            inner: Arc::clone(&self.inner),
        }
    }
}
unsafe impl Send for Context {}
unsafe impl Sync for Context {}
impl ReaderState {
    
    
    pub fn new<T: Into<CString>>(
        name: T,
        current_state: State,
    ) -> ReaderState {
        ReaderState {
            inner: ffi::SCARD_READERSTATE {
                szReader: name.into().into_raw(),
                
                pvUserData: null_mut(),
                dwCurrentState: current_state.bits(),
                dwEventState: State::UNAWARE.bits(),
                cbAtr: 0,
                rgbAtr: [0; ffi::ATR_BUFFER_SIZE],
            },
        }
    }
    
    pub fn name(&self) -> &CStr {
        
        
        unsafe { CStr::from_ptr(self.inner.szReader) }
    }
    
    pub fn atr(&self) -> &[u8] {
        &self.inner.rgbAtr[0..self.inner.cbAtr as usize]
    }
    
    pub fn event_state(&self) -> State {
        State::from_bits_truncate(self.inner.dwEventState)
    }
    
    
    
    
    
    pub fn event_count(&self) -> u32 {
        ((self.inner.dwEventState & 0xFFFF_0000) >> 16) as u32
    }
    
    pub fn sync_current_state(&mut self) {
        
        
        
        self.inner.dwCurrentState = self.inner.dwEventState;
    }
}
impl Drop for ReaderState {
    fn drop(&mut self) {
        
        unsafe { CString::from_raw(self.inner.szReader as *mut c_char) };
    }
}
impl Card {
    
    
    
    
    
    
    
    
    
    
    pub fn transaction(
        &mut self,
    ) -> Result<Transaction, Error> {
        unsafe {
            try_pcsc!(ffi::SCardBeginTransaction(
                self.handle,
            ));
            Ok(Transaction {
                card: self,
            })
        }
    }
    
    
    
    
    
    
    pub fn reconnect(
        &mut self,
        share_mode: ShareMode,
        preferred_protocols: Protocols,
        initialization: Disposition,
    ) -> Result<(), Error> {
        unsafe {
            let mut raw_active_protocol: DWORD = DUMMY_DWORD;
            try_pcsc!(ffi::SCardReconnect(
                self.handle,
                share_mode.into_raw(),
                preferred_protocols.bits(),
                initialization.into_raw(),
                &mut raw_active_protocol,
            ));
            self.active_protocol = Protocol::from_raw(raw_active_protocol);
            Ok(())
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn disconnect(
        mut self,
        disposition: Disposition,
    ) -> Result<(), (Card, Error)> {
        unsafe {
            let err = ffi::SCardDisconnect(
                self.handle,
                disposition.into_raw(),
            );
            if err != ffi::SCARD_S_SUCCESS {
                return Err((self, Error::from_raw(err)));
            }
            
            std::ptr::drop_in_place(&mut self._context);
            forget(self);
            Ok(())
        }
    }
    
    
    
    
    
    
    
    pub fn status(
        &self,
    ) -> Result<(Status, Protocol), Error> {
        unsafe {
            let mut raw_status: DWORD = DUMMY_DWORD;
            let mut raw_protocol: DWORD = DUMMY_DWORD;
            try_pcsc!(ffi::SCardStatus(
                self.handle,
                null_mut(),
                null_mut(),
                &mut raw_status,
                &mut raw_protocol,
                null_mut(),
                null_mut(),
            ));
            let status = Status::from_bits_truncate(raw_status);
            let protocol = Protocol::from_raw(raw_protocol);
            Ok((status, protocol))
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn get_attribute<'buf>(
        &self,
        attribute: Attribute,
        buffer: &'buf mut [u8],
    ) -> Result<&'buf [u8], Error> {
        unsafe {
            assert!(buffer.len() <= std::u32::MAX as usize);
            let mut attribute_len = buffer.len() as DWORD;
            try_pcsc!(ffi::SCardGetAttrib(
                self.handle,
                attribute.into_raw(),
                buffer.as_mut_ptr(),
                &mut attribute_len,
            ));
            Ok(&buffer[0..attribute_len as usize])
        }
    }
    
    
    
    
    
    
    pub fn get_attribute_len(
        &self,
        attribute: Attribute,
    ) -> Result<usize, Error> {
        unsafe {
            let mut attribute_len = DUMMY_DWORD;
            try_pcsc!(ffi::SCardGetAttrib(
                self.handle,
                attribute.into_raw(),
                null_mut(),
                &mut attribute_len,
            ));
            Ok(attribute_len as usize)
        }
    }
    
    
    
    
    
    
    pub fn set_attribute(
        &self,
        attribute: Attribute,
        attribute_data: &[u8],
    ) -> Result<(), Error> {
        unsafe {
            assert!(attribute_data.len() <= std::u32::MAX as usize);
            try_pcsc!(ffi::SCardSetAttrib(
                self.handle,
                attribute.into_raw(),
                attribute_data.as_ptr(),
                attribute_data.len() as DWORD,
            ));
            Ok(())
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn transmit<'buf>(
        &self,
        send_buffer: &[u8],
        receive_buffer: &'buf mut [u8],
    ) -> Result<&'buf [u8], Error> {
        let send_pci = get_protocol_pci(self.active_protocol);
        let recv_pci = null_mut();
        assert!(receive_buffer.len() <= std::u32::MAX as usize);
        let mut receive_len = receive_buffer.len() as DWORD;
        unsafe {
            assert!(send_buffer.len() <= std::u32::MAX as usize);
            try_pcsc!(ffi::SCardTransmit(
                self.handle,
                send_pci,
                send_buffer.as_ptr(),
                send_buffer.len() as DWORD,
                recv_pci,
                receive_buffer.as_mut_ptr(),
                &mut receive_len,
            ));
            Ok(&receive_buffer[0..receive_len as usize])
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn control<'buf>(
        &self,
        
        
        control_code: DWORD,
        send_buffer: &[u8],
        receive_buffer: &'buf mut [u8],
    ) -> Result<&'buf [u8], Error> {
        let mut receive_len: DWORD = DUMMY_DWORD;
        unsafe {
            assert!(send_buffer.len() <= std::u32::MAX as usize);
            assert!(receive_buffer.len() <= std::u32::MAX as usize);
            try_pcsc!(ffi::SCardControl(
                self.handle,
                control_code,
                send_buffer.as_ptr(),
                send_buffer.len() as DWORD,
                receive_buffer.as_mut_ptr(),
                receive_buffer.len() as DWORD,
                &mut receive_len,
            ));
            Ok(&receive_buffer[0..receive_len as usize])
        }
    }
}
impl Drop for Card {
    fn drop(&mut self) {
        unsafe {
            
            
            
            
            
            let _err = ffi::SCardDisconnect(
                self.handle,
                Disposition::ResetCard.into_raw(),
            );
        }
    }
}
unsafe impl Send for Card {}
unsafe impl Sync for Card {}
impl<'tx> Transaction<'tx> {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn end(
        self,
        disposition: Disposition,
    ) -> Result<(), (Transaction<'tx>, Error)> {
        unsafe {
            let err = ffi::SCardEndTransaction(
                self.card.handle,
                disposition.into_raw(),
            );
            if err != 0 {
                return Err((self, Error::from_raw(err)));
            }
            
            forget(self);
            Ok(())
        }
    }
}
impl<'tx> Drop for Transaction<'tx> {
    fn drop(&mut self) {
        unsafe {
            
            
            
            
            
            let _err = ffi::SCardEndTransaction(
                self.card.handle,
                Disposition::LeaveCard.into_raw(),
            );
        }
    }
}
impl<'tx> Deref for Transaction<'tx> {
    type Target = Card;
    fn deref(&self) -> &Card {
        self.card
    }
}