66import java .net .InetAddress ;
77import java .nio .ByteBuffer ;
88import java .nio .channels .FileChannel ;
9+ import java .util .Arrays ;
910import java .util .Map ;
1011
1112public 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 ;
1614 private static byte METADATE_START_MARKER [] = { (byte ) 0xAB , (byte ) 0xCD ,
1715 (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 ;
1821 private final FileChannel fc ;
1922
2023 public Reader (File dataSource ) throws MaxMindDbException , IOException {
@@ -51,16 +54,16 @@ public Reader(File dataSource) throws MaxMindDbException, IOException {
5154 // XXX - right?
5255 this .dataSectionEnd = start - METADATE_START_MARKER .length ;
5356
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 );
5564
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 ());
6265 if (DEBUG ) {
63- Log .debug (metadata .toString ());
66+ Log .debug (this . metadata .toString ());
6467 }
6568 }
6669
@@ -74,12 +77,21 @@ Object dataForAddress(InetAddress address) throws MaxMindDbException,
7477 return null ;
7578 }
7679
80+ this .fc .position (pointer );
7781 return this .resolveDataPointer (pointer );
7882 }
7983
80- long findAddressInTree (InetAddress address ) throws MaxMindDbException {
84+ long findAddressInTree (InetAddress address ) throws MaxMindDbException ,
85+ IOException {
8186 byte [] rawAddress = address .getAddress ();
8287
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+
8395 if (DEBUG ) {
8496 Log .debugNewLine ();
8597 Log .debug ("IP address" , address );
@@ -92,27 +104,29 @@ long findAddressInTree(InetAddress address) throws MaxMindDbException {
92104 long nodeNum = 0 ;
93105
94106 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 );
98110
99- int record = nodes [bit ];
111+ long record = nodes [bit ];
100112
101113 if (DEBUG ) {
114+ Log .debug ("Nodes" , Arrays .toString (nodes ));
102115 Log .debug ("Bit #" , i );
103116 Log .debug ("Bit value" , bit );
104117 Log .debug ("Record" , bit == 1 ? "right" : "left" );
118+ // Log.debug("Node count", this.metadata.nodeCount);
105119 Log .debug ("Record value" , record );
106120 }
107121
108- if (record == this .nodeCount ) {
122+ if (record == this .metadata . nodeCount ) {
109123 if (DEBUG ) {
110124 Log .debug ("Record is empty" );
111125 }
112126 return 0 ;
113127 }
114128
115- if (record >= this .nodeCount ) {
129+ if (record >= this .metadata . nodeCount ) {
116130 if (DEBUG ) {
117131 Log .debug ("Record is a data pointer" );
118132 }
@@ -130,20 +144,61 @@ int record = nodes[bit];
130144 throw new MaxMindDbException ("Something bad happened" );
131145 }
132146
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 );
135152
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+ }
136189 }
137190
138191 private Object resolveDataPointer (long pointer ) throws MaxMindDbException ,
139192 IOException {
140- long resolved = (pointer - this .nodeCount ) + this .searchTreeSize ();
193+ long resolved = (pointer - this .metadata .nodeCount )
194+ + this .metadata .searchTreeSize ;
141195
142196 if (DEBUG ) {
143- long treeSize = this .searchTreeSize () ;
197+ long treeSize = this .metadata . searchTreeSize ;
144198
145199 Log .debug ("Resolved data pointer" , "( " + pointer + " - "
146- + this .nodeCount + " ) + " + treeSize + " = " + resolved );
200+ + this .metadata .nodeCount + " ) + " + treeSize + " = "
201+ + resolved );
147202
148203 }
149204
@@ -152,10 +207,6 @@ private Object resolveDataPointer(long pointer) throws MaxMindDbException,
152207 return this .decoder .decode (resolved ).getObject ();
153208 }
154209
155- private long searchTreeSize () {
156- throw new AssertionError ("not implemented" );
157- }
158-
159210 /*
160211 * And here I though searching a file was a solved problem.
161212 *
@@ -181,4 +232,8 @@ private long findMetadataStart() throws IOException {
181232 }
182233 return -1 ;
183234 }
235+
236+ public Metadata getMetadata () {
237+ return this .metadata ;
238+ }
184239}
0 commit comments