1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ :copyright: ©2018 by IPIP.net
4
+ """
5
+
6
+ import ipaddress
7
+ import json
8
+ from .meta import MetaData
9
+ from .info import IPInfo
10
+ from .util import bytes2long
11
+
12
+
13
+ class Reader :
14
+
15
+ meta = {}
16
+ data = b""
17
+
18
+ file = False
19
+ file_size = 0
20
+
21
+ v4offset = 0
22
+ v6offsetCache = {}
23
+
24
+ def __init__ (self , name ):
25
+ self .file = open (name , "rb" )
26
+ self .data = self .file .read ()
27
+ self .file_size = len (self .data )
28
+
29
+ meta_length = bytes2long (self .data [0 ], self .data [1 ], self .data [2 ], self .data [3 ])
30
+ meta = json .loads (self .data [4 :meta_length + 4 ])
31
+
32
+ self .meta = MetaData (** meta )
33
+ self .data = self .data [4 + meta_length :]
34
+
35
+ def _find_node (self , ip ):
36
+
37
+ if ip .version == 6 :
38
+ bit_count = 128
39
+ else :
40
+ bit_count = 32
41
+
42
+ i = 0
43
+ node = 0
44
+ key = ip .packed [0 :2 ]
45
+ if bit_count == 32 :
46
+ if self .v4offset == 0 :
47
+ i = 0
48
+ while i < 96 :
49
+ if i >= 80 :
50
+ node = self .read_node (node , 1 )
51
+ else :
52
+ node = self .read_node (node , 0 )
53
+ i += 1
54
+ self .v4offset = node
55
+ else :
56
+ node = self .v4offset
57
+ else :
58
+ val = self .v6offsetCache .get (key , - 1 )
59
+ if val > - 1 :
60
+ i = 16
61
+ node = val
62
+
63
+ while i < bit_count :
64
+ if node > self .meta .node_count :
65
+ break
66
+ node = self .read_node (node , (1 & (ip .packed [i >> 3 ] >> 7 - (i % 8 ))))
67
+ i += 1
68
+ if i == 16 :
69
+ self .v6offsetCache [key ] = node
70
+
71
+ return node
72
+
73
+ def read_node (self , node , idx ):
74
+ off = idx * 4 + node * 8
75
+ return bytes2long (self .data [off ], self .data [off + 1 ], self .data [off + 2 ], self .data [off + 3 ])
76
+
77
+ def _resolve (self , node ):
78
+ resolved = node - self .meta .node_count + self .meta .node_count * 8
79
+ size = bytes2long (0 , 0 , self .data [resolved ], self .data [resolved + 1 ])
80
+ return self .data [resolved + 2 :resolved + 2 + size ]
81
+
82
+ def find (self , addr , language = "CN" ):
83
+ node = self ._find_node (ipaddress .ip_address (addr ))
84
+ if node is None :
85
+ return None
86
+
87
+ bytes = self ._resolve (node )
88
+ if bytes is None :
89
+ return None
90
+
91
+ tmp = bytes .decode ("utf-8" ).split ("\t " )
92
+
93
+ off = self .meta .languages .get (language )
94
+ if off is None :
95
+ return None
96
+
97
+ return tmp [off :off + len (self .meta .fields )]
98
+
99
+ def find_map (self , addr , language = 'CN' ):
100
+ loc = self .find (addr , language )
101
+ if loc is None :
102
+ return None
103
+ m = {}
104
+ for idx , value in enumerate (self .meta .fields ):
105
+ m [value ] = loc [idx ]
106
+ return m
107
+
108
+ def find_info (self , addr , language = 'CN' ):
109
+ m = self .find_map (addr , language )
110
+ if m is None :
111
+ return None
112
+ return IPInfo (** m )
0 commit comments