33import java .io .IOException ;
44import java .math .BigInteger ;
55import java .nio .ByteBuffer ;
6- import java .nio .channels .FileChannel ;
76import java .nio .charset .Charset ;
87
98import com .fasterxml .jackson .databind .JsonNode ;
1918import com .fasterxml .jackson .databind .node .TextNode ;
2019
2120public class Decoder {
22- private final FileChannel in ;
2321
2422 private final boolean DEBUG ;
2523 // XXX - This is only for unit testings. We should possibly make a
@@ -29,14 +27,15 @@ public class Decoder {
2927
3028 private final ObjectMapper objectMapper ;
3129
30+ private final ByteBuffer mmap ;
31+
3232 class Result {
3333 private final JsonNode node ;
3434 private long offset ;
3535
3636 Result (JsonNode node , long offset ) {
3737 this .node = node ;
3838 this .offset = offset ;
39-
4039 }
4140
4241 JsonNode getNode () {
@@ -53,22 +52,22 @@ void setOffset(long offset) {
5352
5453 }
5554
56- public Decoder (FileChannel in , long pointerBase ) {
57- this .in = in ;
55+ public Decoder (ByteBuffer mmap , long pointerBase ) {
5856 this .pointerBase = pointerBase ;
57+ this .mmap = mmap ;
5958 this .objectMapper = new ObjectMapper ();
6059 this .DEBUG = System .getenv ().get ("MAXMIND_DB_DECODER_DEBUG" ) != null ;
6160 }
6261
6362 public Result decode (long offset ) throws MaxMindDbException , IOException {
64- this .in .position (offset );
63+ this .mmap .position ((int ) offset );
64+
6565 if (this .DEBUG ) {
6666 Log .debug ("Offset" , String .valueOf (offset ));
6767 }
6868
69- ByteBuffer buffer = ByteBuffer .wrap (new byte [1 ]);
70- this .in .read (buffer );
71- int ctrlByte = 0xFF & buffer .get (0 );
69+ int ctrlByte = 0xFF & this .mmap .get ();
70+
7271 offset ++;
7372
7473 if (this .DEBUG ) {
@@ -96,9 +95,7 @@ public Result decode(long offset) throws MaxMindDbException, IOException {
9695 }
9796
9897 if (type .equals (Type .EXTENDED )) {
99- buffer = ByteBuffer .wrap (new byte [1 ]);
100- this .in .read (buffer );
101- int nextByte = buffer .get (0 );
98+ int nextByte = this .mmap .get ();
10299
103100 if (this .DEBUG ) {
104101 Log .debug ("Next byte" , nextByte );
@@ -147,35 +144,31 @@ public Result decode(long offset) throws MaxMindDbException, IOException {
147144 Log .debug ("Size" , size );
148145 }
149146
150- buffer = ByteBuffer .wrap (new byte [size ]);
151- this .in .read (buffer );
152- byte [] bytes = buffer .array ();
153-
154147 long new_offset = offset + size ;
155148 switch (type ) {
156149 case UTF8_STRING :
157- TextNode s = new TextNode (Decoder .decodeString (bytes ));
150+ TextNode s = new TextNode (this .decodeString (size ));
158151 return new Result (s , new_offset );
159152 case DOUBLE :
160- DoubleNode d = Decoder .decodeDouble (bytes );
153+ DoubleNode d = this .decodeDouble (size );
161154 return new Result (d , new_offset );
162155 case BYTES :
163- BinaryNode b = new BinaryNode (Decoder . decodeBytes ( bytes ));
156+ BinaryNode b = new BinaryNode (this . getByteArray ( size ));
164157 return new Result (b , new_offset );
165158 case UINT16 :
166- IntNode i = Decoder .decodeUint16 (bytes );
159+ IntNode i = this .decodeUint16 (size );
167160 return new Result (i , new_offset );
168161 case UINT32 :
169- LongNode l = Decoder .decodeUint32 (bytes );
162+ LongNode l = this .decodeUint32 (size );
170163 return new Result (l , new_offset );
171164 case INT32 :
172- IntNode int32 = Decoder .decodeInt32 (bytes );
165+ IntNode int32 = this .decodeInt32 (size );
173166 return new Result (int32 , new_offset );
174167 case UINT64 :
175- BigIntegerNode bi = Decoder . decodeUint64 ( bytes );
168+ BigIntegerNode bi = this . decodeBigInteger ( size );
176169 return new Result (bi , new_offset );
177170 case UINT128 :
178- BigIntegerNode uint128 = Decoder . decodeUint128 ( bytes );
171+ BigIntegerNode uint128 = this . decodeBigInteger ( size );
179172 return new Result (uint128 , new_offset );
180173 default :
181174 throw new MaxMindDbException ("Unknown or unexpected type: "
@@ -187,25 +180,17 @@ public Result decode(long offset) throws MaxMindDbException, IOException {
187180 private final long [] pointerValueOffset = { 0 , 0 , 1 << 11 ,
188181 (((long ) 1 ) << 19 ) + ((1 ) << 11 ), 0 };
189182
190- private Result decodePointer (int ctrlByte , long offset ) throws IOException {
183+ private Result decodePointer (int ctrlByte , long offset ) {
191184
192185 int pointerSize = ((ctrlByte >>> 3 ) & 0x3 ) + 1 ;
193186
194187 if (this .DEBUG ) {
195188 Log .debug ("Pointer size" , String .valueOf (pointerSize ));
196189 }
197190
198- ByteBuffer buffer = ByteBuffer .wrap (new byte [pointerSize + 1 ]);
199-
200- this .in .read (buffer , this .in .position () - 1 );
201-
202- if (this .DEBUG ) {
203- Log .debug ("Buffer" , buffer );
204- }
205-
206- buffer .put (0 , pointerSize == 4 ? (byte ) 0 : (byte ) (ctrlByte & 0x7 ));
191+ int base = pointerSize == 4 ? (byte ) 0 : (byte ) (ctrlByte & 0x7 );
207192
208- long packed = Util .decodeLong (buffer . array () );
193+ long packed = this .decodeLong (base , pointerSize );
209194
210195 if (this .DEBUG ) {
211196 Log .debug ("Packed pointer" , String .valueOf (packed ));
@@ -224,36 +209,55 @@ private Result decodePointer(int ctrlByte, long offset) throws IOException {
224209 return new Result (new LongNode (pointer ), offset + pointerSize );
225210 }
226211
227- private static String decodeString (byte [] bytes ) {
228- return new String (bytes , Charset .forName ("UTF-8" ));
212+ private String decodeString (int size ) {
213+ ByteBuffer buffer = this .mmap .slice ();
214+ buffer .limit (size );
215+ return Charset .forName ("UTF-8" ).decode (buffer ).toString ();
229216 }
230217
231- // XXX - nop
232- private static byte [] decodeBytes (byte [] bytes ) {
233- return bytes ;
218+ IntNode decodeUint16 (int size ) {
219+ return new IntNode (this .decodeInteger (size ));
234220 }
235221
236- static IntNode decodeUint16 ( byte [] bytes ) {
237- return new IntNode (Util .decodeInteger (bytes ));
222+ IntNode decodeInt32 ( int size ) {
223+ return new IntNode (this .decodeInteger (size ));
238224 }
239225
240- static IntNode decodeInt32 ( byte [] bytes ) {
241- return new IntNode ( Util .decodeInteger (bytes ) );
226+ private int decodeInteger ( int size ) {
227+ return this .decodeInteger (0 , size );
242228 }
243229
244- static LongNode decodeUint32 (byte [] bytes ) {
245- return new LongNode (Util .decodeLong (bytes ));
230+ private int decodeInteger (int base , int size ) {
231+ int integer = base ;
232+ for (int i = 0 ; i < size ; i ++) {
233+ integer = (integer << 8 ) | (this .mmap .get () & 0xFF );
234+ }
235+ return integer ;
246236 }
247237
248- static BigIntegerNode decodeUint64 (byte [] bytes ) {
249- return new BigIntegerNode (new BigInteger (1 , bytes ));
238+ LongNode decodeUint32 (int size ) {
239+ return new LongNode (this .decodeLong (size ));
240+ }
241+
242+ long decodeLong (int size ) {
243+ return this .decodeLong (0 , size );
250244 }
251245
252- static BigIntegerNode decodeUint128 (byte [] bytes ) {
246+ long decodeLong (long base , int size ) {
247+ long longInt = base ;
248+ for (int i = 0 ; i < size ; i ++) {
249+ longInt = (longInt << 8 ) | (this .mmap .get () & 0xFF );
250+ }
251+ return longInt ;
252+ }
253+
254+ BigIntegerNode decodeBigInteger (int size ) {
255+ byte [] bytes = this .getByteArray (size );
253256 return new BigIntegerNode (new BigInteger (1 , bytes ));
254257 }
255258
256- private static DoubleNode decodeDouble (byte [] bytes ) {
259+ private DoubleNode decodeDouble (int size ) {
260+ byte [] bytes = this .getByteArray (size );
257261 return new DoubleNode (Double .parseDouble (new String (bytes , Charset
258262 .forName ("US-ASCII" ))));
259263 }
@@ -331,22 +335,24 @@ private long[] sizeFromCtrlByte(int ctrlByte, long offset)
331335
332336 int bytesToRead = size - 28 ;
333337
334- ByteBuffer buffer = ByteBuffer .wrap (new byte [bytesToRead ]);
335- this .in .read (buffer );
336-
337338 if (size == 29 ) {
338- int i = Util .decodeInteger (buffer . array () );
339+ int i = this .decodeInteger (bytesToRead );
339340 size = 29 + i ;
340341 } else if (size == 30 ) {
341- int i = Util .decodeInteger (buffer . array () );
342+ int i = this .decodeInteger (bytesToRead );
342343 size = 285 + i ;
343344 } else {
344- buffer . put ( 0 , ( byte ) ( buffer . get ( 0 ) & 0x0F ));
345- int i = Util . decodeInteger ( buffer . array ( ));
345+ int i = this . decodeInteger ( bytesToRead )
346+ & ( 0x0FFFFFFF >>> ( 32 - ( 8 * bytesToRead ) ));
346347 size = 65821 + i ;
347348 }
348349
349350 return new long [] { size , offset + bytesToRead };
350351 }
351352
353+ private byte [] getByteArray (int length ) {
354+ byte [] bytes = new byte [length ];
355+ this .mmap .get (bytes );
356+ return bytes ;
357+ }
352358}
0 commit comments