6
6
import java .net .InetAddress ;
7
7
import java .nio .ByteBuffer ;
8
8
import java .nio .channels .FileChannel ;
9
+ import java .util .Arrays ;
9
10
import java .util .Map ;
10
11
11
12
public class Reader {
12
- private static final boolean DEBUG = true ;
13
- private Decoder decoder ;
14
- private long nodeCount ;
15
- private final long dataSectionEnd ;
13
+ private static int DATA_SECTION_SEPARATOR_SIZE = 16 ;
16
14
private static byte METADATE_START_MARKER [] = { (byte ) 0xAB , (byte ) 0xCD ,
17
15
(byte ) 0xEF , 'M' , 'a' , 'x' , 'M' , 'i' , 'n' , 'd' , '.' , 'c' , 'o' , 'm' };
16
+
17
+ private static final boolean DEBUG = true ;
18
+ private final Decoder decoder ;
19
+ private final Metadata metadata ;
20
+ private final long dataSectionEnd ;
18
21
private final FileChannel fc ;
19
22
20
23
public Reader (File dataSource ) throws MaxMindDbException , IOException {
@@ -51,16 +54,16 @@ public Reader(File dataSource) throws MaxMindDbException, IOException {
51
54
// XXX - right?
52
55
this .dataSectionEnd = start - METADATE_START_MARKER .length ;
53
56
54
- Decoder decoder = new Decoder (this .fc , 0 );
57
+ Decoder metadataDecoder = new Decoder (this .fc , 0 );
58
+
59
+ this .metadata = new Metadata ((Map <String , Object >) metadataDecoder
60
+ .decode (start ).getObject ());
61
+
62
+ this .decoder = new Decoder (this .fc , this .metadata .searchTreeSize
63
+ + DATA_SECTION_SEPARATOR_SIZE );
55
64
56
- // FIXME - pretty ugly that I am setting the position outside of the
57
- // decoder. Move this all into
58
- // the decoder and make sure it is thread safe
59
- this .fc .position (start );
60
- Metadata metadata = new Metadata ((Map <String , Object >) decoder
61
- .decode (0 ).getObject ());
62
65
if (DEBUG ) {
63
- Log .debug (metadata .toString ());
66
+ Log .debug (this . metadata .toString ());
64
67
}
65
68
}
66
69
@@ -74,12 +77,21 @@ Object dataForAddress(InetAddress address) throws MaxMindDbException,
74
77
return null ;
75
78
}
76
79
80
+ this .fc .position (pointer );
77
81
return this .resolveDataPointer (pointer );
78
82
}
79
83
80
- long findAddressInTree (InetAddress address ) throws MaxMindDbException {
84
+ long findAddressInTree (InetAddress address ) throws MaxMindDbException ,
85
+ IOException {
81
86
byte [] rawAddress = address .getAddress ();
82
87
88
+ // XXX sort of wasteful
89
+ if (rawAddress .length == 4 && this .metadata .ipVersion == 6 ) {
90
+ byte [] newAddress = new byte [16 ];
91
+ System .arraycopy (rawAddress , 0 , newAddress , 12 , rawAddress .length );
92
+ rawAddress = newAddress ;
93
+ }
94
+
83
95
if (DEBUG ) {
84
96
Log .debugNewLine ();
85
97
Log .debug ("IP address" , address );
@@ -92,27 +104,29 @@ long findAddressInTree(InetAddress address) throws MaxMindDbException {
92
104
long nodeNum = 0 ;
93
105
94
106
for (int i = 0 ; i < rawAddress .length * 8 ; i ++) {
95
- byte b = rawAddress [i / 8 ];
96
- int bit = 1 & (b >> 7 - i );
97
- int [] nodes = this .readNode (nodeNum );
107
+ int b = 0xFF & rawAddress [i / 8 ];
108
+ int bit = 1 & (b >> 7 - ( i % 8 ) );
109
+ long [] nodes = this .readNode (nodeNum );
98
110
99
- int record = nodes [bit ];
111
+ long record = nodes [bit ];
100
112
101
113
if (DEBUG ) {
114
+ Log .debug ("Nodes" , Arrays .toString (nodes ));
102
115
Log .debug ("Bit #" , i );
103
116
Log .debug ("Bit value" , bit );
104
117
Log .debug ("Record" , bit == 1 ? "right" : "left" );
118
+ // Log.debug("Node count", this.metadata.nodeCount);
105
119
Log .debug ("Record value" , record );
106
120
}
107
121
108
- if (record == this .nodeCount ) {
122
+ if (record == this .metadata . nodeCount ) {
109
123
if (DEBUG ) {
110
124
Log .debug ("Record is empty" );
111
125
}
112
126
return 0 ;
113
127
}
114
128
115
- if (record >= this .nodeCount ) {
129
+ if (record >= this .metadata . nodeCount ) {
116
130
if (DEBUG ) {
117
131
Log .debug ("Record is a data pointer" );
118
132
}
@@ -130,20 +144,61 @@ int record = nodes[bit];
130
144
throw new MaxMindDbException ("Something bad happened" );
131
145
}
132
146
133
- private int [] readNode (long nodeNum ) {
134
- throw new AssertionError ("not implemented" );
147
+ private long [] readNode (long nodeNumber ) throws IOException ,
148
+ MaxMindDbException {
149
+ ByteBuffer buffer = ByteBuffer
150
+ .wrap (new byte [this .metadata .nodeByteSize ]);
151
+ this .fc .position (nodeNumber * this .metadata .nodeByteSize );
135
152
153
+ this .fc .read (buffer );
154
+
155
+ if (DEBUG ) {
156
+ Log .debug ("Node bytes" , buffer );
157
+ }
158
+ return this .splitNodeIntoRecords (buffer );
159
+ }
160
+
161
+ private long [] splitNodeIntoRecords (ByteBuffer bytes )
162
+ throws MaxMindDbException {
163
+ long [] nodes = new long [2 ];
164
+ switch (this .metadata .recordSize .intValue ()) {
165
+ case 24 :
166
+ nodes [0 ] = Util .decodeLong (Arrays .copyOfRange (bytes .array (), 0 ,
167
+ 3 ));
168
+ nodes [1 ] = Util .decodeLong (Arrays .copyOfRange (bytes .array (), 3 ,
169
+ 6 ));
170
+ return nodes ;
171
+ case 28 :
172
+ nodes [0 ] = Util .decodeLong (Arrays .copyOfRange (bytes .array (), 0 ,
173
+ 3 ));
174
+ nodes [1 ] = Util .decodeLong (Arrays .copyOfRange (bytes .array (), 4 ,
175
+ 7 ));
176
+ nodes [0 ] = ((0xF0 & bytes .get (3 )) << 24 ) | nodes [0 ];
177
+ nodes [1 ] = ((0x0F & bytes .get (3 )) << 24 ) | nodes [1 ];
178
+ return nodes ;
179
+ case 32 :
180
+ nodes [0 ] = Util .decodeLong (Arrays .copyOfRange (bytes .array (), 0 ,
181
+ 4 ));
182
+ nodes [1 ] = Util .decodeLong (Arrays .copyOfRange (bytes .array (), 4 ,
183
+ 8 ));
184
+ return nodes ;
185
+ default :
186
+ throw new MaxMindDbException ("Unknown record size: "
187
+ + this .metadata .recordSize );
188
+ }
136
189
}
137
190
138
191
private Object resolveDataPointer (long pointer ) throws MaxMindDbException ,
139
192
IOException {
140
- long resolved = (pointer - this .nodeCount ) + this .searchTreeSize ();
193
+ long resolved = (pointer - this .metadata .nodeCount )
194
+ + this .metadata .searchTreeSize ;
141
195
142
196
if (DEBUG ) {
143
- long treeSize = this .searchTreeSize () ;
197
+ long treeSize = this .metadata . searchTreeSize ;
144
198
145
199
Log .debug ("Resolved data pointer" , "( " + pointer + " - "
146
- + this .nodeCount + " ) + " + treeSize + " = " + resolved );
200
+ + this .metadata .nodeCount + " ) + " + treeSize + " = "
201
+ + resolved );
147
202
148
203
}
149
204
@@ -152,10 +207,6 @@ private Object resolveDataPointer(long pointer) throws MaxMindDbException,
152
207
return this .decoder .decode (resolved ).getObject ();
153
208
}
154
209
155
- private long searchTreeSize () {
156
- throw new AssertionError ("not implemented" );
157
- }
158
-
159
210
/*
160
211
* And here I though searching a file was a solved problem.
161
212
*
@@ -181,4 +232,8 @@ private long findMetadataStart() throws IOException {
181
232
}
182
233
return -1 ;
183
234
}
235
+
236
+ public Metadata getMetadata () {
237
+ return this .metadata ;
238
+ }
184
239
}
0 commit comments