ts-ip2region2 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,496 @@
1
+ // Copyright 2022 The Ip2Region Authors. All rights reserved.
2
+ // Use of this source code is governed by a Apache2.0-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ // ---
6
+ // @Author Lion <chenxin619315@gmail.com>
7
+ // @Date 2022/06/27
8
+
9
+ #include "xdb_api.h"
10
+ #include <ctype.h>
11
+
12
+ // for Linux
13
+ #ifdef XDB_LINUX
14
+ #include "sys/time.h"
15
+ #endif
16
+
17
+ #ifdef XDB_WINDOWS
18
+ #include <time.h>
19
+ #endif
20
+
21
+ // @Note: since 2023/10/13 to compatible with the windows system
22
+ #ifdef XDB_WINDOWS
23
+ static int winsock_initialized = 0;
24
+ XDB_PUBLIC(int) xdb_init_winsock() {
25
+ if (winsock_initialized == 1) {
26
+ return 0;
27
+ }
28
+
29
+ WSADATA wsaData;
30
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
31
+ return -1;
32
+ }
33
+ winsock_initialized = 1;
34
+ return 0;
35
+ }
36
+
37
+ XDB_PUBLIC(void) xdb_clean_winsock() {
38
+ if (winsock_initialized == 1) {
39
+ WSACleanup();
40
+ winsock_initialized = 0;
41
+ }
42
+ }
43
+
44
+ XDB_PRIVATE(int) gettimeofday(struct timeval* tp, void* tzp) {
45
+ time_t clock;
46
+ struct tm tm;
47
+ SYSTEMTIME wtm;
48
+ GetLocalTime(&wtm);
49
+ tm.tm_year = wtm.wYear - 1900;
50
+ tm.tm_mon = wtm.wMonth - 1;
51
+ tm.tm_mday = wtm.wDay;
52
+ tm.tm_hour = wtm.wHour;
53
+ tm.tm_min = wtm.wMinute;
54
+ tm.tm_sec = wtm.wSecond;
55
+ tm.tm_isdst = -1;
56
+ clock = mktime(&tm);
57
+ tp->tv_sec = clock;
58
+ tp->tv_usec = wtm.wMilliseconds * 1000;
59
+ return (0);
60
+ }
61
+ #else
62
+ XDB_PUBLIC(int) xdb_init_winsock() {return 0;}
63
+ XDB_PUBLIC(void) xdb_clean_winsock() {}
64
+ #endif
65
+
66
+ // --- xdb buffer function implementations
67
+
68
+ XDB_PUBLIC(xdb_header_t *) xdb_load_header(FILE *handle) {
69
+ xdb_header_t *header;
70
+ unsigned int size = xdb_header_info_length;
71
+
72
+ // entry alloc
73
+ header = (xdb_header_t *) xdb_malloc(sizeof(xdb_header_t));
74
+ if (header == NULL) {
75
+ return NULL;
76
+ }
77
+
78
+ if (fseek(handle, 0, SEEK_SET) == -1) {
79
+ xdb_free(header);
80
+ return NULL;
81
+ }
82
+
83
+ if (fread(header->buffer, 1,size, handle) != size) {
84
+ xdb_free(header);
85
+ return NULL;
86
+ }
87
+
88
+ // fill the fields
89
+ header->length = size;
90
+ header->version = (unsigned short) xdb_le_get_uint16(header->buffer, 0);
91
+ header->index_policy = (unsigned short) xdb_le_get_uint16(header->buffer, 2);
92
+ header->created_at = xdb_le_get_uint32(header->buffer, 4);
93
+ header->start_index_ptr = xdb_le_get_uint32(header->buffer, 8);
94
+ header->end_index_ptr = xdb_le_get_uint32(header->buffer,12);
95
+
96
+ // since IPv6 supporting
97
+ header->ip_version = xdb_le_get_uint16(header->buffer, 16);
98
+ header->runtime_ptr_bytes = xdb_le_get_uint16(header->buffer, 18);
99
+
100
+ return header;
101
+ }
102
+
103
+ XDB_PUBLIC(xdb_header_t *) xdb_load_header_from_file(const char *db_path) {
104
+ xdb_header_t *header;
105
+ FILE *handle = fopen(db_path, "rb");
106
+ if (handle == NULL) {
107
+ return NULL;
108
+ }
109
+
110
+ header = xdb_load_header(handle);
111
+ fclose(handle);
112
+ return header;
113
+ }
114
+
115
+ XDB_PUBLIC(void) xdb_free_header(void *ptr) {
116
+ xdb_header_t *header = (xdb_header_t *) ptr;
117
+ if (header->length > 0) {
118
+ header->length = 0;
119
+ xdb_free(header);
120
+ }
121
+ }
122
+
123
+ // --- vector index
124
+
125
+ XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index(FILE *handle) {
126
+ xdb_vector_index_t *v_index;
127
+ unsigned int size = xdb_vector_index_length;
128
+
129
+ // seek to the vector index offset
130
+ if (fseek(handle, xdb_header_info_length, SEEK_SET) == -1) {
131
+ return NULL;
132
+ }
133
+
134
+ // do the buffer read
135
+ v_index = (xdb_vector_index_t *) xdb_malloc(sizeof(xdb_vector_index_t));
136
+ if (v_index == NULL) {
137
+ return NULL;
138
+ }
139
+
140
+ v_index->length = size;
141
+ if (fread(v_index->buffer, 1, size, handle) != size) {
142
+ xdb_free(v_index);
143
+ return NULL;
144
+ }
145
+
146
+ return v_index;
147
+ }
148
+
149
+ XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index_from_file(const char *db_path) {
150
+ xdb_vector_index_t *v_index;
151
+ FILE *handle = fopen(db_path, "rb");
152
+ if (handle == NULL) {
153
+ return NULL;
154
+ }
155
+
156
+ v_index = xdb_load_vector_index(handle);
157
+ fclose(handle);
158
+ return v_index;
159
+ }
160
+
161
+ XDB_PUBLIC(void) xdb_free_vector_index(void *ptr) {
162
+ xdb_vector_index_t *v_index = (xdb_vector_index_t *) ptr;
163
+ if (v_index->length > 0) {
164
+ v_index->length = 0;
165
+ xdb_free(v_index);
166
+ }
167
+ }
168
+
169
+ // --- content buffer
170
+
171
+ XDB_PUBLIC(xdb_content_t *) xdb_load_content(FILE *handle) {
172
+ unsigned int size;
173
+ xdb_content_t *content;
174
+
175
+ // determine the file size
176
+ if (fseek(handle, 0, SEEK_END) == -1) {
177
+ return NULL;
178
+ }
179
+
180
+ size = (unsigned int) ftell(handle);
181
+ if (fseek(handle, 0, SEEK_SET) == -1) {
182
+ return NULL;
183
+ }
184
+
185
+ // do the file read
186
+ content = (xdb_content_t *) xdb_malloc(sizeof(xdb_content_t));
187
+ if (content == NULL) {
188
+ return NULL;
189
+ }
190
+
191
+ // do the buffer alloc
192
+ content->buffer = (char *) xdb_malloc(size);
193
+ if (content->buffer == NULL) {
194
+ xdb_free(content);
195
+ return NULL;
196
+ }
197
+
198
+ // read the content into the buffer
199
+ content->length = size;
200
+ if (fread(content->buffer, 1, size, handle) != size) {
201
+ xdb_free(content);
202
+ return NULL;
203
+ }
204
+
205
+ return content;
206
+ }
207
+
208
+ XDB_PUBLIC(xdb_content_t *) xdb_load_content_from_file(const char *db_path) {
209
+ xdb_content_t *content;
210
+ FILE *handle = fopen(db_path, "rb");
211
+ if (handle == NULL) {
212
+ return NULL;
213
+ }
214
+
215
+ content = xdb_load_content(handle);
216
+ fclose(handle);
217
+ return content;
218
+ }
219
+
220
+ XDB_PUBLIC(void) xdb_free_content(void *ptr) {
221
+ xdb_content_t *content = (xdb_content_t *) ptr;
222
+ if (content->length > 0) {
223
+ content->length = 0;
224
+ xdb_free(content->buffer);
225
+ content->buffer = NULL;
226
+ xdb_free(content);
227
+ }
228
+ }
229
+
230
+ XDB_PUBLIC(int) xdb_verify_from_header(FILE *handle, xdb_header_t *header) {
231
+ int runtime_ptr_bytes = 0; // runtime ptr bytes
232
+ if (header->version == xdb_structure_20) {
233
+ runtime_ptr_bytes = 4;
234
+ } else if (header->version == xdb_structure_30) {
235
+ runtime_ptr_bytes = header->runtime_ptr_bytes;
236
+ } else {
237
+ return 2;
238
+ }
239
+
240
+ // 1, confirm the xdb file size.
241
+ // to ensure that the maximum file pointer does not overflow.
242
+ int err = fseek(handle, 0L, SEEK_END);
243
+ if (err != 0) {
244
+ return 3;
245
+ }
246
+
247
+ long int fileBytes = ftell(handle);
248
+ long int maxFilePtr = (1L << (runtime_ptr_bytes * 8)) - 1;
249
+ // printf("fileBytes: %ld, maxFilePtr: %ld\n", fileBytes, maxFilePtr);
250
+ if (fileBytes > maxFilePtr) {
251
+ return 4;
252
+ }
253
+
254
+ return 0;
255
+ }
256
+
257
+ XDB_PUBLIC(int) xdb_verify(FILE *handle) {
258
+ xdb_header_t *header = xdb_load_header(handle);
259
+ if (header == NULL) {
260
+ return 1;
261
+ }
262
+
263
+ int errcode = xdb_verify_from_header(handle, header);
264
+ if (errcode != 0) {
265
+ goto done;
266
+ }
267
+
268
+ // what next ?
269
+ done:
270
+ xdb_free_header(header);
271
+ return errcode;
272
+ }
273
+
274
+ XDB_PUBLIC(int) xdb_verify_from_file(const char *db_path) {
275
+ FILE *handle = fopen(db_path, "rb");
276
+ if (handle == NULL) {
277
+ return -1;
278
+ }
279
+
280
+ int r = xdb_verify(handle);
281
+ fclose(handle);
282
+ return r;
283
+ }
284
+
285
+ // --- End content buffer
286
+
287
+
288
+ // --- ip version
289
+
290
+ // ip compare for IPv4
291
+ // ip1 - with Big endian byte order parsed from an input
292
+ // ip2 - with Little endian byte order read from the xdb index.
293
+ // to compatiable with the Little Endian encoded IPv4 on xdb 2.0.
294
+ XDB_PRIVATE(int) _ipv4_sub_compare(const bytes_ip_t *ip_bytes, int bytes, const char *buffer, int offset) {
295
+ register int i0, i1;
296
+ for (int i = 0, j = offset + bytes - 1; i < bytes; i++, j--) {
297
+ i0 = ip_bytes[i];
298
+ i1 = buffer[j] & 0xFF;
299
+ if (i0 > i1) {
300
+ return 1;
301
+ } else if (i0 < i1) {
302
+ return -1;
303
+ }
304
+ }
305
+ return 0;
306
+ }
307
+
308
+ static xdb_version_t _ip_version_list[] = {
309
+ // 14 = 4 + 4 + 2 + 4
310
+ {xdb_ipv4_id, "IPv4", xdb_ipv4_bytes, xdb_v4_index_size, _ipv4_sub_compare},
311
+
312
+ // 38 = 16 + 16 + 2 + 4
313
+ {xdb_ipv6_id, "IPv6", xdb_ipv6_bytes, xdb_v6_index_size, xdb_ip_sub_compare},
314
+
315
+ // END
316
+ {0, NULL, 0, 0, NULL}
317
+ };
318
+
319
+ XDB_PUBLIC(xdb_version_t *) xdb_version_v4() {
320
+ return &_ip_version_list[0];
321
+ }
322
+
323
+ XDB_PUBLIC(xdb_version_t *) xdb_version_v6() {
324
+ return &_ip_version_list[1];
325
+ }
326
+
327
+ XDB_PUBLIC(int) xdb_version_is_v4(const xdb_version_t *version) {
328
+ return version->id == xdb_ipv4_id;
329
+ }
330
+
331
+ XDB_PUBLIC(int) xdb_version_is_v6(const xdb_version_t *version) {
332
+ return version->id == xdb_ipv6_id;
333
+ }
334
+
335
+ XDB_PUBLIC(xdb_version_t *) xdb_version_from_name(char *name) {
336
+ // to upper case the name
337
+ for (int i = 0; name[i] != '\0'; i++) {
338
+ name[i] = toupper((unsigned char) name[i]);
339
+ }
340
+
341
+ if (strcmp(name, "V4") == 0 || strcmp(name, "IPV4") == 0) {
342
+ return xdb_version_v4();
343
+ } else if (strcmp(name, "V6") == 0 || strcmp(name, "IPV6") == 0) {
344
+ return xdb_version_v6();
345
+ } else {
346
+ return NULL;
347
+ }
348
+ }
349
+
350
+ XDB_PUBLIC(xdb_version_t *) xdb_version_from_header(xdb_header_t *header) {
351
+ // Old structure with ONLY IPv4 supports
352
+ if (header->version == xdb_structure_20) {
353
+ return xdb_version_v4();
354
+ }
355
+
356
+ // structure 3.0 with IPv6 supporting
357
+ if (header->version != xdb_structure_30) {
358
+ return NULL;
359
+ }
360
+
361
+ if (header->ip_version == xdb_ipv4_id) {
362
+ return xdb_version_v4();
363
+ } else if (header->ip_version == xdb_ipv6_id) {
364
+ return xdb_version_v6();
365
+ } else {
366
+ return NULL;
367
+ }
368
+ }
369
+
370
+ // --- END ip version
371
+
372
+ XDB_PUBLIC(long) xdb_now() {
373
+ struct timeval c_time;
374
+ gettimeofday(&c_time, NULL);
375
+ return c_time.tv_sec * (int)1e6 + c_time.tv_usec;
376
+ }
377
+
378
+ XDB_PUBLIC(unsigned int) xdb_le_get_uint32(const char *buffer, int offset) {
379
+ return (
380
+ ((buffer[offset ]) & 0x000000FF) |
381
+ ((buffer[offset+1] << 8) & 0x0000FF00) |
382
+ ((buffer[offset+2] << 16) & 0x00FF0000) |
383
+ ((buffer[offset+3] << 24) & 0xFF000000)
384
+ );
385
+ }
386
+
387
+ XDB_PUBLIC(int) xdb_le_get_uint16(const char *buffer, int offset) {
388
+ return (
389
+ ((buffer[offset ]) & 0x000000FF) |
390
+ ((buffer[offset+1] << 8) & 0x0000FF00)
391
+ );
392
+ }
393
+
394
+ XDB_PUBLIC(xdb_version_t *) xdb_parse_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
395
+ // version check
396
+ if (strchr(ip_string, '.') != NULL && strchr(ip_string, ':') == NULL) {
397
+ return xdb_parse_v4_ip(ip_string, buffer, length);
398
+ } else if (strchr(ip_string, ':') != NULL) {
399
+ return xdb_parse_v6_ip(ip_string, buffer, length);
400
+ }
401
+
402
+ return NULL;
403
+ }
404
+
405
+ XDB_PUBLIC(xdb_version_t *) xdb_parse_v4_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
406
+ struct in_addr addr;
407
+
408
+ // buffer length checking
409
+ if (length < xdb_ipv4_bytes) {
410
+ return NULL;
411
+ }
412
+
413
+ if (inet_pton(AF_INET, ip_string, &addr) != 1) {
414
+ return NULL;
415
+ }
416
+
417
+ // encode the address to buffer with big endian byte bufffer.
418
+ buffer[0] = (addr.s_addr) & 0xFF;
419
+ buffer[1] = (addr.s_addr >> 8) & 0xFF;
420
+ buffer[2] = (addr.s_addr >> 16) & 0xFF;
421
+ buffer[3] = (addr.s_addr >> 24) & 0xFF;
422
+ return XDB_IPv4;
423
+ }
424
+
425
+ XDB_PUBLIC(xdb_version_t *) xdb_parse_v6_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
426
+ struct in6_addr addr;
427
+
428
+ // buffer length checking
429
+ if (length < xdb_ipv6_bytes) {
430
+ return NULL;
431
+ }
432
+
433
+ if (inet_pton(AF_INET6, ip_string, &addr) != 1) {
434
+ return NULL;
435
+ }
436
+
437
+ memcpy(buffer, addr.s6_addr, xdb_ipv6_bytes);
438
+ return XDB_IPv6;
439
+ }
440
+
441
+ XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *ip_bytes, int bytes, char *ip_string, size_t length) {
442
+ if (bytes == xdb_ipv4_bytes) {
443
+ return xdb_v4_ip_to_string(ip_bytes, ip_string, length);
444
+ } else if (bytes == xdb_ipv6_bytes) {
445
+ return xdb_v6_ip_to_string(ip_bytes, ip_string, length);
446
+ }
447
+
448
+ return -1;
449
+ }
450
+
451
+ XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
452
+ if (!ip_bytes || !ip_string || length == 0) {
453
+ return -1;
454
+ }
455
+
456
+ // buffer length checking
457
+ if (length < INET_ADDRSTRLEN) {
458
+ return -1;
459
+ }
460
+
461
+ if (inet_ntop(AF_INET, ip_bytes, ip_string, length) == NULL) {
462
+ return -1;
463
+ }
464
+
465
+ return 0;
466
+ }
467
+
468
+ XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
469
+ if (!ip_bytes || !ip_string || length == 0) {
470
+ return -1;
471
+ }
472
+
473
+ if (length < INET6_ADDRSTRLEN) {
474
+ return -1;
475
+ }
476
+
477
+ if (inet_ntop(AF_INET6, ip_bytes, ip_string, length) == NULL) {
478
+ return -1;
479
+ }
480
+
481
+ return 0;
482
+ }
483
+
484
+ XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *ip1, int bytes, const char *buffer, int offset) {
485
+ register int i, i1, i2;
486
+ for (i = 0; i < bytes; i++) {
487
+ i1 = ip1[i];
488
+ i2 = buffer[offset + i] & 0xFF;
489
+ if (i1 > i2) {
490
+ return 1;
491
+ } else if (i1 < i2) {
492
+ return -1;
493
+ }
494
+ }
495
+ return 0;
496
+ }
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "ts-ip2region2",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript-first ip2region implementation with native Node.js addon. Ultra-fast IPv4/IPv6 geolocation queries.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "node-gyp rebuild",
9
+ "compile": "tsc",
10
+ "build:all": "npm run build && npm run compile",
11
+ "rebuild": "node-gyp rebuild",
12
+ "clean": "node-gyp clean",
13
+ "test": "npm run build:all && node test.js",
14
+ "example": "npm run build:all && node example.js",
15
+ "prepublishOnly": "npm run build:all",
16
+ "semantic-release": "semantic-release"
17
+ },
18
+ "keywords": [
19
+ "typescript",
20
+ "ip2region",
21
+ "geolocation",
22
+ "ipv4",
23
+ "ipv6",
24
+ "native-addon",
25
+ "high-performance",
26
+ "xdb",
27
+ "ip-lookup"
28
+ ],
29
+ "author": "Steven Qiang <git@qiangmou.ren>",
30
+ "license": "Apache-2.0",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/Steven-Qiang/ts-ip2region2.git"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/Steven-Qiang/ts-ip2region2/issues"
37
+ },
38
+ "homepage": "https://github.com/Steven-Qiang/ts-ip2region2#readme",
39
+ "dependencies": {
40
+ "node-addon-api": "^7.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.19.19",
44
+ "node-gyp": "^10.0.0",
45
+ "typescript": "^5.9.3",
46
+ "semantic-release": "^22.0.0",
47
+ "@semantic-release/changelog": "^6.0.0",
48
+ "@semantic-release/commit-analyzer": "^11.0.0",
49
+ "@semantic-release/git": "^10.0.0",
50
+ "@semantic-release/github": "^9.0.0",
51
+ "@semantic-release/npm": "^11.0.0",
52
+ "@semantic-release/release-notes-generator": "^12.0.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=16.0.0"
56
+ },
57
+ "os": [
58
+ "darwin",
59
+ "linux",
60
+ "win32"
61
+ ],
62
+ "cpu": [
63
+ "x64",
64
+ "arm64"
65
+ ],
66
+ "files": [
67
+ "dist/**/*",
68
+ "addon.cpp",
69
+ "ip2region/**/*",
70
+ "binding.gyp",
71
+ "README.md",
72
+ "README_CN.md"
73
+ ],
74
+ "gypfile": true,
75
+ "publishConfig": {
76
+ "access": "public"
77
+ }
78
+ }