1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
// go_usage.go — Example of using libthaiidcard from Go.
//
// Build the shared library first:
// make shared
//
// Then run:
// go run examples/go_usage.go [reader_name]
package main
/*
#cgo !windows LDFLAGS: -ldl
#include <stdlib.h>
#include <stdio.h>
// ---------------------------------------------------------------------------
// Platform abstraction for dynamic library loading
// ---------------------------------------------------------------------------
#ifdef _WIN32
#include <windows.h>
typedef HMODULE lib_handle;
static inline lib_handle lib_load(const char* name) { return LoadLibraryA(name); }
static inline void* lib_sym(lib_handle h, const char* n) { return (void*)GetProcAddress(h, n); }
static inline int lib_close(lib_handle h) { return FreeLibrary(h) ? 0 : -1; }
static const char* lib_error(void) {
static char buf[256];
DWORD err = GetLastError();
if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL))
return buf;
snprintf(buf, sizeof(buf), "error code %lu", (unsigned long)err);
return buf;
}
#else
#include <dlfcn.h>
typedef void* lib_handle;
#define lib_load(name) dlopen(name, RTLD_LAZY)
#define lib_sym(handle,n) dlsym(handle, n)
#define lib_close(handle) dlclose(handle)
#define lib_error() dlerror()
#endif
// Opaque handle type.
typedef struct thaiid_card_data thaiid_card_data;
// Function pointer types.
typedef thaiid_card_data* (*read_fn)(const char*, int, int, int);
typedef void (*free_fn)(thaiid_card_data*);
typedef const char* (*get_last_error_fn)(void);
typedef const char* (*get_str_fn)(const thaiid_card_data*);
// Globals (populated by loadLibrary).
static lib_handle g_lib = NULL;
static read_fn fn_read = NULL;
static free_fn fn_free = NULL;
static get_last_error_fn fn_get_last_error = NULL;
static get_str_fn fn_get_cid = NULL;
static get_str_fn fn_get_name_thai = NULL;
static get_str_fn fn_get_name_en = NULL;
static get_str_fn fn_get_dob = NULL;
static get_str_fn fn_get_gender = NULL;
static get_str_fn fn_get_card_issuer = NULL;
static get_str_fn fn_get_issue_date = NULL;
static get_str_fn fn_get_expire_date = NULL;
static get_str_fn fn_get_address = NULL;
static get_str_fn fn_get_face_image = NULL;
static get_str_fn fn_get_laser_id = NULL;
static get_str_fn fn_get_main_inscl = NULL;
static get_str_fn fn_get_sub_inscl = NULL;
static get_str_fn fn_get_main_hospital = NULL;
static get_str_fn fn_get_sub_hospital = NULL;
static get_str_fn fn_get_paid_type = NULL;
static get_str_fn fn_get_nhso_issue_date = NULL;
static get_str_fn fn_get_nhso_expire_date = NULL;
static get_str_fn fn_get_nhso_update_date = NULL;
static get_str_fn fn_get_change_hospital_amount = NULL;
static int loadLibrary(const char* path) {
g_lib = lib_load(path);
if (!g_lib) {
fprintf(stderr, "Failed to load %s: %s\n", path, lib_error());
return -1;
}
#define RESOLVE(var, name) do { \
*(void**)(&var) = lib_sym(g_lib, name); \
if (!var) { fprintf(stderr, "Missing symbol: %s (%s)\n", name, lib_error()); lib_close(g_lib); return -1; } \
} while(0)
RESOLVE(fn_read, "thaiid_read");
RESOLVE(fn_free, "thaiid_free");
RESOLVE(fn_get_last_error, "thaiid_get_last_error");
RESOLVE(fn_get_cid, "thaiid_get_cid");
RESOLVE(fn_get_name_thai, "thaiid_get_name_thai");
RESOLVE(fn_get_name_en, "thaiid_get_name_en");
RESOLVE(fn_get_dob, "thaiid_get_dob");
RESOLVE(fn_get_gender, "thaiid_get_gender");
RESOLVE(fn_get_card_issuer, "thaiid_get_card_issuer");
RESOLVE(fn_get_issue_date, "thaiid_get_issue_date");
RESOLVE(fn_get_expire_date, "thaiid_get_expire_date");
RESOLVE(fn_get_address, "thaiid_get_address");
RESOLVE(fn_get_face_image, "thaiid_get_face_image");
RESOLVE(fn_get_laser_id, "thaiid_get_laser_id");
RESOLVE(fn_get_main_inscl, "thaiid_get_main_inscl");
RESOLVE(fn_get_sub_inscl, "thaiid_get_sub_inscl");
RESOLVE(fn_get_main_hospital, "thaiid_get_main_hospital");
RESOLVE(fn_get_sub_hospital, "thaiid_get_sub_hospital");
RESOLVE(fn_get_paid_type, "thaiid_get_paid_type");
RESOLVE(fn_get_nhso_issue_date, "thaiid_get_nhso_issue_date");
RESOLVE(fn_get_nhso_expire_date, "thaiid_get_nhso_expire_date");
RESOLVE(fn_get_nhso_update_date, "thaiid_get_nhso_update_date");
RESOLVE(fn_get_change_hospital_amount, "thaiid_get_change_hospital_amount");
#undef RESOLVE
return 0;
}
static void unloadLibrary(void) {
if (g_lib) lib_close(g_lib);
}
// Wrappers callable from Go.
thaiid_card_data* c_read(const char* reader, int face, int nhso, int laser) {
return fn_read(reader, face, nhso, laser);
}
void c_free(thaiid_card_data* d) { fn_free(d); }
const char* c_get_last_error(void) { return fn_get_last_error(); }
const char* c_get_cid(thaiid_card_data* d) { return fn_get_cid(d); }
const char* c_get_name_thai(thaiid_card_data* d) { return fn_get_name_thai(d); }
const char* c_get_name_en(thaiid_card_data* d) { return fn_get_name_en(d); }
const char* c_get_dob(thaiid_card_data* d) { return fn_get_dob(d); }
const char* c_get_gender(thaiid_card_data* d) { return fn_get_gender(d); }
const char* c_get_card_issuer(thaiid_card_data* d) { return fn_get_card_issuer(d); }
const char* c_get_issue_date(thaiid_card_data* d) { return fn_get_issue_date(d); }
const char* c_get_expire_date(thaiid_card_data* d) { return fn_get_expire_date(d); }
const char* c_get_address(thaiid_card_data* d) { return fn_get_address(d); }
const char* c_get_face_image(thaiid_card_data* d) { return fn_get_face_image(d); }
const char* c_get_laser_id(thaiid_card_data* d) { return fn_get_laser_id(d); }
const char* c_get_main_inscl(thaiid_card_data* d) { return fn_get_main_inscl(d); }
const char* c_get_sub_inscl(thaiid_card_data* d) { return fn_get_sub_inscl(d); }
const char* c_get_main_hospital(thaiid_card_data* d) { return fn_get_main_hospital(d); }
const char* c_get_sub_hospital(thaiid_card_data* d) { return fn_get_sub_hospital(d); }
const char* c_get_paid_type(thaiid_card_data* d) { return fn_get_paid_type(d); }
const char* c_get_nhso_issue_date(thaiid_card_data* d) { return fn_get_nhso_issue_date(d); }
const char* c_get_nhso_expire_date(thaiid_card_data* d) { return fn_get_nhso_expire_date(d); }
const char* c_get_nhso_update_date(thaiid_card_data* d) { return fn_get_nhso_update_date(d); }
const char* c_get_change_hospital_amount(thaiid_card_data* d) { return fn_get_change_hospital_amount(d); }
*/
import "C"
import (
"fmt"
"os"
"runtime"
)
// libraryFilename returns the shared library name for the current platform.
func libraryFilename() string
// findLibrary searches common locations for libthaiidcard.
func findLibrary() string
func main()
func printCardData(data *C.thaiid_card_data)