smartcard 0.2.0-mswin32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE cPcscIoRequest;
4
+
5
+ /* Custom free for Smartcard::PCSC::IoRequest. */
6
+ static void PCSC_IoRequest_free(SCARD_IO_REQUEST *_request) {
7
+ if(_request != NULL)
8
+ xfree(_request);
9
+ }
10
+
11
+ /* Custom allocation for Smartcard::PCSC::Card. Wraps a SCARD_IO_REQUEST. */
12
+ static VALUE PCSC_IoRequest_alloc(VALUE klass) {
13
+ SCARD_IO_REQUEST *request;
14
+
15
+ VALUE rbIoRequest = Data_Make_Struct(klass, SCARD_IO_REQUEST, NULL, PCSC_IoRequest_free, request);
16
+ return rbIoRequest;
17
+ }
18
+
19
+ /* :Document-method: protocol
20
+ * call-seq:
21
+ * io_request.protocol --> protocol
22
+ *
23
+ * The protocol of this instance.
24
+ *
25
+ * The returned protocol is a number, and should be checked against one of the Smartcard::PCSC::PROTOCOL_ constants.
26
+ */
27
+ static VALUE PCSC_IoRequest_get_protocol(VALUE self) {
28
+ SCARD_IO_REQUEST *request;
29
+
30
+ Data_Get_Struct(self, SCARD_IO_REQUEST, request);
31
+ if(request == NULL) return Qnil;
32
+
33
+ return UINT2NUM(request->dwProtocol);
34
+ }
35
+
36
+ /* :Document-method: protocol=
37
+ * call-seq:
38
+ * io_request.protocol = protocol
39
+ *
40
+ * Sets the protocol of this instance.
41
+ *
42
+ * +protocol+:: use one of the Smartcard::PCSC::PROTOCOL_ constants
43
+ */
44
+ static VALUE PCSC_IoRequest_set_protocol(VALUE self, VALUE rbProtocol) {
45
+ SCARD_IO_REQUEST *request;
46
+
47
+ Data_Get_Struct(self, SCARD_IO_REQUEST, request);
48
+ if(request == NULL) return self;
49
+
50
+ request->dwProtocol = NUM2UINT(rbProtocol);
51
+ return self;
52
+ }
53
+
54
+ #ifdef MAKE_RDOC_HAPPY
55
+ mSmartcard = rb_define_module("Smartcard");
56
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
57
+ #endif
58
+
59
+ /* :Document-class: Smartcard::PCSC::IoRequest
60
+ * Protocol information used in Smartcard::PCSC::Card#transmit.
61
+ * Wraps a _SCARD_IO_REQUEST_ structure.
62
+ *
63
+ * I know the name is retarded, but it reflects the PC/SC name well. The choice makes sense given that this
64
+ * is an API meant for people familiar with the PC/SC specification.
65
+ */
66
+ void Init_PCSC_IoRequest() {
67
+ cPcscIoRequest = rb_define_class_under(mPcsc, "IoRequest", rb_cObject);
68
+ rb_define_alloc_func(cPcscIoRequest, PCSC_IoRequest_alloc);
69
+ rb_define_method(cPcscIoRequest, "protocol", PCSC_IoRequest_get_protocol, 0);
70
+ rb_define_method(cPcscIoRequest, "protocol=", PCSC_IoRequest_set_protocol, 1);
71
+ }
72
+
73
+ /* Retrieves the SCARD_IO_REQUEST wrapped into a Smartcard::PCSC::IoRequest instance. */
74
+ int _PCSC_IoRequest_lowlevel_get(VALUE rbIoRequest, SCARD_IO_REQUEST **io_request) {
75
+ SCARD_IO_REQUEST *request;
76
+
77
+ if(TYPE(rbIoRequest) == T_NIL || TYPE(rbIoRequest) == T_FALSE) {
78
+ *io_request = NULL;
79
+ return 1;
80
+ }
81
+ if(TYPE(rbIoRequest) != T_DATA || RDATA(rbIoRequest)->dfree != (void (*)(void *))PCSC_IoRequest_free)
82
+ return 0;
83
+
84
+ Data_Get_Struct(rbIoRequest, SCARD_IO_REQUEST, request);
85
+ *io_request = request;
86
+ return 1;
87
+ }
@@ -0,0 +1,10 @@
1
+ #include "pcsc.h"
2
+
3
+ void Init_pcsc() {
4
+ Init_PCSC_Namespace();
5
+ Init_PCSC_ReaderStates();
6
+ Init_PCSC_IoRequest();
7
+ Init_PCSC_Context();
8
+ Init_PCSC_Card();
9
+ Init_PCSC_Consts();
10
+ }
@@ -0,0 +1,82 @@
1
+ #include <string.h>
2
+ #include "pcsc.h"
3
+
4
+ /* Converts a multi-string "str1\0str_2\0str3\0\0" into a Ruby array of Ruby strings. */
5
+ VALUE PCSC_Internal_multistring_to_ruby_array(char *mstr, size_t mstr_len) {
6
+ VALUE rbArray, rbString;
7
+ size_t i, start_offset;
8
+
9
+ rbArray = rb_ary_new();
10
+ for(i = 0; i < mstr_len; i++) {
11
+ if(mstr[i] == '\0') break;
12
+ start_offset = i;
13
+ for(; i < mstr_len; i++)
14
+ if(mstr[i] == '\0') break;
15
+ rbString = rb_str_new(mstr + start_offset, i - start_offset);
16
+ rb_ary_push(rbArray, rbString);
17
+ }
18
+ return rbArray;
19
+ }
20
+
21
+ /* Constructs a multi-string "str1\0str_2\0str3\0\0". Takes nil, a string, or an array of strings.
22
+ * The returned buffer must be released with xfree.
23
+ * If false is returned, something went wrong and the method did not return a buffer.
24
+ */
25
+ int PCSC_Internal_ruby_strings_to_multistring(VALUE rbStrings, char **strings) {
26
+ VALUE *array_elements;
27
+ char *buffer;
28
+ size_t string_length, array_length, buffer_length, i;
29
+
30
+ /* nil -> NULL */
31
+ if(TYPE(rbStrings) == T_NIL || TYPE(rbStrings) == T_FALSE) {
32
+ *strings = NULL;
33
+ return 1;
34
+ }
35
+ /* string -> [string] */
36
+ if(TYPE(rbStrings) == T_STRING) {
37
+ string_length = RSTRING(rbStrings)->len;
38
+ buffer = ALLOC_N(char, string_length + 2);
39
+ memcpy(buffer, RSTRING(rbStrings)->ptr, string_length);
40
+ buffer[string_length] = buffer[string_length + 1] = '\0';
41
+ *strings = buffer;
42
+ return 1;
43
+ }
44
+ /* array -> array */
45
+ if(TYPE(rbStrings) == T_ARRAY) {
46
+ /* compute buffer length */
47
+ array_length = RARRAY(rbStrings)->len;
48
+ array_elements = RARRAY(rbStrings)->ptr;
49
+ buffer_length = 1; /* for the trailing '\0' */
50
+ for(i = 0; i < array_length; i++) {
51
+ if(TYPE(array_elements[i]) != T_STRING)
52
+ return 0;
53
+ buffer_length += RSTRING(array_elements[i])->len + 1;
54
+ }
55
+
56
+ /* concatenate strings into buffer */
57
+ buffer = ALLOC_N(char, buffer_length);
58
+ for(buffer_length = 0, i = 0; i < array_length; i++) {
59
+ string_length = RSTRING(array_elements[i])->len;
60
+ memcpy(buffer + buffer_length, RSTRING(array_elements[i])->ptr, string_length);
61
+ buffer[buffer_length] = '\0';
62
+ buffer_length += string_length + 1;
63
+ }
64
+ buffer[buffer_length] = '\0';
65
+ *strings = buffer;
66
+ return 1;
67
+ }
68
+
69
+ return 0;
70
+ }
71
+
72
+ #if defined(WIN32)
73
+ char scard_error_buffer[128];
74
+
75
+ /* Produces a string for an error code yielded by the SCard* PC/SC functions. Returns a static global buffer. */
76
+ char *pcsc_stringify_error(DWORD scard_error) {
77
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
78
+ NULL, scard_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
79
+ scard_error_buffer, sizeof(scard_error_buffer), NULL );
80
+ return scard_error_buffer;
81
+ }
82
+ #endif
@@ -0,0 +1,18 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE mSmartcard;
4
+ VALUE mPcsc;
5
+
6
+ /* :Document-class: Smartcard::PCSC
7
+ * Bindings to the PC/SC Smartcard API.
8
+ *
9
+ */
10
+ static void Init_PCSC() {
11
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
12
+ }
13
+
14
+ void Init_PCSC_Namespace() {
15
+ mSmartcard = rb_define_module("Smartcard");
16
+ Init_PCSC();
17
+ }
18
+
@@ -0,0 +1,326 @@
1
+ #include "pcsc.h"
2
+
3
+ VALUE cPcscReaderStates;
4
+
5
+ /* Wraps an array of SCARD_READERSTATE elements. */
6
+ struct PCSCReaderStates {
7
+ size_t states_count;
8
+ SCARD_READERSTATE *states;
9
+ };
10
+
11
+ /* Custom free for Smartcard::PCSC::ReaderStates. Also releases the referenced buffers (for the reader names). */
12
+ static void PCSC_ReaderStates_free(struct PCSCReaderStates *_states) {
13
+ size_t i;
14
+ if(_states != NULL) {
15
+ if(_states->states != NULL) {
16
+ for(i = 0; i < _states->states_count; i++) {
17
+ if(_states->states[i].szReader != NULL)
18
+ xfree((char *)_states->states[i].szReader);
19
+ }
20
+ xfree(_states->states);
21
+ }
22
+ xfree(_states);
23
+ }
24
+ }
25
+
26
+ /* Custom allocation for Smartcard::PCSC::ReaderStates. Wraps a reference to an array of SCARD_READERSTATE. */
27
+ static VALUE PCSC_ReaderStates_alloc(VALUE klass) {
28
+ struct PCSCReaderStates *states;
29
+
30
+ VALUE rbReaderStates = Data_Make_Struct(klass, struct PCSCReaderStates, NULL, PCSC_ReaderStates_free, states);
31
+ states->states_count = 0;
32
+ states->states = NULL;
33
+ return rbReaderStates;
34
+ }
35
+
36
+ /* :Document-method: new
37
+ * call-seq:
38
+ * new(num_states) --> reader_states
39
+ *
40
+ * Creates an array of +num_states+ reader state elements.
41
+ * The states are unusable until they are assigned reader names by calling ReaderStates#set_reader_name_of.
42
+ */
43
+ static VALUE PCSC_ReaderStates_initialize(VALUE self, VALUE rbNumStates) {
44
+ struct PCSCReaderStates *states;
45
+ size_t states_count, i;
46
+
47
+ Data_Get_Struct(self, struct PCSCReaderStates, states);
48
+
49
+ states_count = NUM2UINT(rbNumStates);
50
+ if(states_count > 0) {
51
+ states->states = ALLOC_N(SCARD_READERSTATE, states_count);
52
+ if(states->states != NULL) {
53
+ states->states_count = states_count;
54
+ for(i = 0; i < states_count; i++) {
55
+ states->states[i].szReader = NULL;
56
+ states->states[i].dwCurrentState = SCARD_STATE_UNAWARE;
57
+ }
58
+ }
59
+ }
60
+ return self;
61
+ }
62
+
63
+ static int _validate_readerstates_args(VALUE rbReaderStates, VALUE rbIndex, struct PCSCReaderStates **states, size_t *index) {
64
+ Data_Get_Struct(rbReaderStates, struct PCSCReaderStates, *states);
65
+ if(*states == NULL) return 0;
66
+
67
+ *index = NUM2UINT(rbIndex);
68
+ if(*index >= (*states)->states_count) {
69
+ rb_raise(rb_eIndexError, "index %u is invalid (states array has %u elements)", *index, (*states)->states_count);
70
+ return 0;
71
+ }
72
+
73
+ return 1;
74
+ }
75
+
76
+ /* :Document-method: current_state_of
77
+ * call-seq:
78
+ * current_state_of(index) --> current_state
79
+ *
80
+ * The current state (_dwCurrentState_ in PC/SC) in the <tt>index</tt>th reader state element.
81
+ * Smartcard::PCSC::Context#get_status_change blocks as long as the reader state equals this value.
82
+ *
83
+ * The returned state is a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
84
+ *
85
+ * +index+:: the 0-based index of the reader state element to be queried
86
+ */
87
+ static VALUE PCSC_ReaderStates_current_state_of(VALUE self, VALUE rbIndex) {
88
+ struct PCSCReaderStates *states;
89
+ size_t index;
90
+
91
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
92
+ return Qnil;
93
+
94
+ return UINT2NUM(states->states[index].dwCurrentState);
95
+ }
96
+
97
+ /* :Document-method: event_state_of
98
+ * call-seq:
99
+ * event_state_of(index) --> event_state
100
+ *
101
+ * The event state (_dwEventState_ in PC/SC) in the <tt>index</tt>th reader state element.
102
+ * Smartcard::PCSC::Context#get_status_change stores the updated reader state in this value.
103
+ *
104
+ * The returned state is a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
105
+ *
106
+ * +index+:: the 0-based index of the reader state element to be queried
107
+ */
108
+ static VALUE PCSC_ReaderStates_event_state_of(VALUE self, VALUE rbIndex) {
109
+ struct PCSCReaderStates *states;
110
+ size_t index;
111
+
112
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
113
+ return Qnil;
114
+
115
+ return UINT2NUM(states->states[index].dwEventState);
116
+ }
117
+
118
+ /* :Document-method: set_current_state_of!
119
+ * call-seq:
120
+ * set_current_state_of!(index, current_state) --> self
121
+ *
122
+ * Sets the current state (_dwCurrentState_ in PC/SC) in the <tt>index</tt>th reader state element.
123
+ * Smartcard::PCSC::Context#get_status_change blocks as long as the reader state equals this value.
124
+ *
125
+ *
126
+ * +index+:: the 0-based index of the reader state element to be modified
127
+ * +current_state+:: a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
128
+ */
129
+ static VALUE PCSC_ReaderStates_set_current_state_of(VALUE self, VALUE rbIndex, VALUE rbCurrentState) {
130
+ struct PCSCReaderStates *states;
131
+ size_t index;
132
+
133
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
134
+ return self;
135
+
136
+ states->states[index].dwCurrentState = NUM2UINT(rbCurrentState);
137
+ return self;
138
+ }
139
+
140
+ /* :Document-method: set_event_state_of!
141
+ * call-seq:
142
+ * set_event_state_of!(index, event_state) --> self
143
+ *
144
+ * Sets the event state (_dwEventState_ in PC/SC) in the <tt>index</tt>th reader state element.
145
+ * Smartcard::PCSC::Context#get_status_change stores the updated reader state in this value.
146
+ *
147
+ * +index+:: the 0-based index of the reader state element to be modified
148
+ * +event_state+:: a bitfield; the bits are defined in the Smartcard::PCSC::STATE_ constants.
149
+ */
150
+ static VALUE PCSC_ReaderStates_set_event_state_of(VALUE self, VALUE rbIndex, VALUE rbEventState) {
151
+ struct PCSCReaderStates *states;
152
+ size_t index;
153
+
154
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
155
+ return self;
156
+
157
+ states->states[index].dwEventState = NUM2UINT(rbEventState);
158
+ return self;
159
+ }
160
+
161
+ /* :Document-method: atr_of
162
+ * call-seq:
163
+ * atr_of(index) --> atr
164
+ *
165
+ * The card ATR string in the <tt>index</tt>th reader state element.
166
+ * Smartcard::PCSC::Context#get_status_change stores the updated ATR string in this value.
167
+ *
168
+ * The returned ATR bytes are wrapped into a string. (don't complain, it's a low-level API)
169
+ *
170
+ * +index+:: the 0-based index of the reader state element to be queried
171
+ */
172
+ static VALUE PCSC_ReaderStates_atr_of(VALUE self, VALUE rbIndex) {
173
+ struct PCSCReaderStates *states;
174
+ size_t index;
175
+
176
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
177
+ return Qnil;
178
+
179
+ return rb_str_new((char *)states->states[index].rgbAtr, states->states[index].cbAtr);
180
+ }
181
+
182
+ /* :Document-method: set_atr_of!
183
+ * call-seq:
184
+ * set_atr_of!(index, atr) --> self
185
+ *
186
+ * Sets the card ATR string in the <tt>index</tt>th reader state element.
187
+ * Smartcard::PCSC::Context#get_status_change stores the updated ATR string in this value.
188
+ *
189
+ * +index+:: the 0-based index of the reader state element to be modified
190
+ * +atr+:: ATR bytes wrapped into a string (low-level API, remember?)
191
+ */
192
+ static VALUE PCSC_ReaderStates_set_atr_of(VALUE self, VALUE rbIndex, VALUE rbAtr) {
193
+ struct PCSCReaderStates *states;
194
+ size_t index;
195
+ VALUE rbFinalAtr;
196
+
197
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
198
+ return self;
199
+
200
+ rbFinalAtr = rb_check_string_type(rbAtr);
201
+ if(NIL_P(rbFinalAtr))
202
+ return self;
203
+
204
+ if(RSTRING(rbFinalAtr)->len > MAX_ATR_SIZE) {
205
+ rb_raise(rb_eArgError, "given ATR is too long (%d characters given; can do at most MAX_ATR_SIZE = %d)", RSTRING(rbFinalAtr)->len, MAX_ATR_SIZE);
206
+ return self;
207
+ }
208
+
209
+ states->states[index].cbAtr = RSTRING(rbAtr)->len;
210
+ memcpy(states->states[index].rgbAtr, RSTRING(rbAtr)->ptr, states->states[index].cbAtr);
211
+ return self;
212
+ }
213
+
214
+ /* :Document-method: reader_name_of
215
+ * call-seq:
216
+ * reader_name_of(index) --> reader_name
217
+ *
218
+ * The name of the reader whose status is represented in the <tt>index</tt>th reader state element.
219
+ * Smartcard::PCSC::Context#get_status_change reads this value, and never updates it.
220
+ *
221
+ * +index+:: the 0-based index of the reader state element to be queried
222
+ */
223
+ static VALUE PCSC_ReaderStates_reader_name_of(VALUE self, VALUE rbIndex) {
224
+ struct PCSCReaderStates *states;
225
+ size_t index;
226
+
227
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
228
+ return Qnil;
229
+
230
+ return rb_str_new2(states->states[index].szReader);
231
+ }
232
+
233
+ /* :Document-method: set_reader_name_of!
234
+ * call-seq:
235
+ * set_reader_name_of!(index, reader_name) --> self
236
+ *
237
+ * The name of the reader whose status is represented in the <tt>index</tt>th reader state element.
238
+ * Smartcard::PCSC::Context#get_status_change reads this value, and never updates it.
239
+ *
240
+ * +index+:: the 0-based index of the reader state element to be modified
241
+ * +reader_name+:: a string-like object containing the reader name to be associated with the state element
242
+ */
243
+ static VALUE PCSC_ReaderStates_set_reader_name_of(VALUE self, VALUE rbIndex, VALUE rbReaderName) {
244
+ struct PCSCReaderStates *states;
245
+ size_t index, reader_name_length;
246
+ VALUE rbFinalReaderName;
247
+
248
+ if(_validate_readerstates_args(self, rbIndex, &states, &index) == 0)
249
+ return self;
250
+
251
+ rbFinalReaderName = rb_check_string_type(rbReaderName);
252
+ if(NIL_P(rbFinalReaderName))
253
+ return self;
254
+
255
+ reader_name_length = RSTRING(rbFinalReaderName)->len;
256
+ if(states->states[index].szReader != NULL)
257
+ xfree((char *)states->states[index].szReader);
258
+ states->states[index].szReader = ALLOC_N(char, reader_name_length + 1);
259
+ if(states->states[index].szReader != NULL) {
260
+ memcpy((char *)states->states[index].szReader, RSTRING(rbFinalReaderName)->ptr, reader_name_length);
261
+ ((char *)states->states[index].szReader)[reader_name_length] = '\0';
262
+ }
263
+ return self;
264
+ }
265
+
266
+ /* :Document-method: acknowledge_events!
267
+ * call-seq:
268
+ * acknowledge_events!() --> self
269
+ *
270
+ * Mass-assigns +current_state+ to +event_state+ for each reader state element.
271
+ * Useful to acknowledge all the status changed communicated after a call to Smartcard::PCSC::Context#get_status_change
272
+ * (and thus prepare for a new call).
273
+ */
274
+ static VALUE PCSC_ReaderStates_acknowledge_events(VALUE self) {
275
+ struct PCSCReaderStates *states;
276
+ size_t i;
277
+
278
+ Data_Get_Struct(self, struct PCSCReaderStates, states);
279
+ if(states != NULL) {
280
+ for(i = 0; i < states->states_count; i++)
281
+ states->states[i].dwCurrentState = states->states[i].dwEventState;
282
+ }
283
+ return self;
284
+ }
285
+
286
+ #ifdef MAKE_RDOC_HAPPY
287
+ mSmartcard = rb_define_module("Smartcard");
288
+ mPcsc = rb_define_module_under(mSmartcard, "PCSC");
289
+ #endif
290
+
291
+ /* :Document-class: Smartcard::PCSC::ReaderStates
292
+ * Tracks reader status information, and is used in Smartcard::PCSC::Context#get_status_change.
293
+ * Wraps an array of <i>SCARD_READERSTATE</i> structures.
294
+ */
295
+ void Init_PCSC_ReaderStates() {
296
+ cPcscReaderStates = rb_define_class_under(mPcsc, "ReaderStates", rb_cObject);
297
+ rb_define_alloc_func(cPcscReaderStates, PCSC_ReaderStates_alloc);
298
+ rb_define_method(cPcscReaderStates, "initialize", PCSC_ReaderStates_initialize, 1);
299
+ rb_define_method(cPcscReaderStates, "current_state_of", PCSC_ReaderStates_current_state_of, 1);
300
+ rb_define_method(cPcscReaderStates, "set_current_state_of!", PCSC_ReaderStates_set_current_state_of, 2);
301
+ rb_define_method(cPcscReaderStates, "event_state_of", PCSC_ReaderStates_event_state_of, 1);
302
+ rb_define_method(cPcscReaderStates, "set_event_state_of!", PCSC_ReaderStates_set_event_state_of, 2);
303
+ rb_define_method(cPcscReaderStates, "reader_name_of", PCSC_ReaderStates_reader_name_of, 1);
304
+ rb_define_method(cPcscReaderStates, "set_reader_name_of!", PCSC_ReaderStates_set_reader_name_of, 2);
305
+ rb_define_method(cPcscReaderStates, "atr_of", PCSC_ReaderStates_atr_of, 1);
306
+ rb_define_method(cPcscReaderStates, "set_atr_of!", PCSC_ReaderStates_set_atr_of, 2);
307
+ rb_define_method(cPcscReaderStates, "acknowledge_events!", PCSC_ReaderStates_acknowledge_events, 0);
308
+ }
309
+
310
+ /* Retrieves the SCARD_READERSTATE array wrapped into a Smartcard::PCSC::ReaderStates instance. */
311
+ int _PCSC_ReaderStates_lowlevel_get(VALUE rbReaderStates, SCARD_READERSTATE **reader_states, size_t *reader_states_count) {
312
+ struct PCSCReaderStates *states;
313
+
314
+ if(TYPE(rbReaderStates) == T_NIL || TYPE(rbReaderStates) == T_FALSE) {
315
+ *reader_states = NULL;
316
+ *reader_states_count = 0;
317
+ return 1;
318
+ }
319
+ if(TYPE(rbReaderStates) != T_DATA || RDATA(rbReaderStates)->dfree != (void (*)(void *))PCSC_ReaderStates_free)
320
+ return 0;
321
+
322
+ Data_Get_Struct(rbReaderStates, struct PCSCReaderStates, states);
323
+ *reader_states = states->states;
324
+ *reader_states_count = states->states_count;
325
+ return 1;
326
+ }