@@ -9,11 +9,13 @@ import (
99 "errors"
1010 "fmt"
1111 "io"
12+ "lukechampine.com/uint128"
1213 "math"
1314 "math/big"
1415 "net"
1516 "os"
1617 "strconv"
18+ "unsafe"
1719)
1820
1921type DBReader interface {
@@ -146,15 +148,15 @@ var category_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
146148
147149const api_version string = "9.5.0"
148150
149- var max_ipv4_range = big . NewInt (4294967295 )
150- var max_ipv6_range = big . NewInt (0 )
151- var from_v4mapped = big . NewInt (281470681743360 )
152- var to_v4mapped = big . NewInt (281474976710655 )
153- var from_6to4 = big . NewInt (0 )
154- var to_6to4 = big . NewInt (0 )
155- var from_teredo = big . NewInt (0 )
156- var to_teredo = big . NewInt (0 )
157- var last_32bits = big . NewInt (4294967295 )
151+ var max_ipv4_range = uint128 . From64 (4294967295 )
152+ var max_ipv6_range = uint128 . From64 (0 )
153+ var from_v4mapped = uint128 . From64 (281470681743360 )
154+ var to_v4mapped = uint128 . From64 (281474976710655 )
155+ var from_6to4 = uint128 . From64 (0 )
156+ var to_6to4 = uint128 . From64 (0 )
157+ var from_teredo = uint128 . From64 (0 )
158+ var to_teredo = uint128 . From64 (0 )
159+ var last_32bits = uint128 . From64 (4294967295 )
158160
159161const countryshort uint32 = 0x000001
160162const countrylong uint32 = 0x000002
@@ -187,10 +189,10 @@ const not_supported string = "This parameter is unavailable for selected data fi
187189const invalid_bin string = "Incorrect IP2Location BIN file format. Please make sure that you are using the latest IP2Location BIN file."
188190
189191// get IP type and calculate IP number; calculates index too if exists
190- func (d * DB ) checkip (ip string ) (iptype uint32 , ipnum * big. Int , ipindex uint32 ) {
192+ func (d * DB ) checkip (ip string ) (iptype uint32 , ipnum uint128. Uint128 , ipindex uint32 ) {
191193 iptype = 0
192- ipnum = big . NewInt (0 )
193- ipnumtmp := big . NewInt (0 )
194+ ipnum = uint128 . From64 (0 )
195+ ipnumtmp := uint128 . From64 (0 )
194196 ipindex = 0
195197 ipaddress := net .ParseIP (ip )
196198
@@ -199,43 +201,43 @@ func (d *DB) checkip(ip string) (iptype uint32, ipnum *big.Int, ipindex uint32)
199201
200202 if v4 != nil {
201203 iptype = 4
202- ipnum . SetBytes ( v4 )
204+ ipnum = uint128 . From64 ( uint64 ( binary . BigEndian . Uint32 ( v4 )) )
203205 } else {
204206 v6 := ipaddress .To16 ()
205207
206208 if v6 != nil {
207209 iptype = 6
208- ipnum .SetBytes (v6 )
210+ ipnum .PutBytes (v6 )
209211
210212 if ipnum .Cmp (from_v4mapped ) >= 0 && ipnum .Cmp (to_v4mapped ) <= 0 {
211213 // ipv4-mapped ipv6 should treat as ipv4 and read ipv4 data section
212214 iptype = 4
213- ipnum .Sub (ipnum , from_v4mapped )
215+ ipnum = ipnum .Sub (from_v4mapped )
214216 } else if ipnum .Cmp (from_6to4 ) >= 0 && ipnum .Cmp (to_6to4 ) <= 0 {
215217 // 6to4 so need to remap to ipv4
216218 iptype = 4
217- ipnum .Rsh (ipnum , 80 )
218- ipnum .And (ipnum , last_32bits )
219+ ipnum = ipnum .Rsh (80 )
220+ ipnum = ipnum .And (last_32bits )
219221 } else if ipnum .Cmp (from_teredo ) >= 0 && ipnum .Cmp (to_teredo ) <= 0 {
220222 // Teredo so need to remap to ipv4
221223 iptype = 4
222- ipnum . Not ( ipnum )
223- ipnum .And (ipnum , last_32bits )
224+ ipnum = uint128. Uint128 { ^ ipnum . Lo , ^ ipnum . Hi }
225+ ipnum = ipnum .And (last_32bits )
224226 }
225227 }
226228 }
227229 }
228230 if iptype == 4 {
229231 if d .meta .ipv4indexed {
230- ipnumtmp .Rsh (ipnum , 16 )
231- ipnumtmp .Lsh (ipnumtmp , 3 )
232- ipindex = uint32 (ipnumtmp .Add (ipnumtmp , big . NewInt ( int64 (d .meta .ipv4indexbaseaddr ))).Uint64 () )
232+ ipnumtmp = ipnum .Rsh (16 )
233+ ipnumtmp = ipnumtmp .Lsh (3 )
234+ ipindex = uint32 (ipnumtmp .Add (uint128 . From64 ( uint64 (d .meta .ipv4indexbaseaddr ))).Lo )
233235 }
234236 } else if iptype == 6 {
235237 if d .meta .ipv6indexed {
236- ipnumtmp .Rsh (ipnum , 112 )
237- ipnumtmp .Lsh (ipnumtmp , 3 )
238- ipindex = uint32 (ipnumtmp .Add (ipnumtmp , big . NewInt ( int64 (d .meta .ipv6indexbaseaddr ))).Uint64 () )
238+ ipnumtmp = ipnum .Rsh (112 )
239+ ipnumtmp = ipnumtmp .Lsh (3 )
240+ ipindex = uint32 (ipnumtmp .Add (uint128 . From64 ( uint64 (d .meta .ipv6indexbaseaddr ))).Lo )
239241 }
240242 }
241243 return
@@ -290,33 +292,33 @@ func (d *DB) readuint32(pos uint32) (uint32, error) {
290292}
291293
292294// read unsigned 128-bit integer from slices
293- func (d * DB ) readuint128_row (row []byte , pos uint32 ) * big. Int {
294- retval := big . NewInt (0 )
295+ func (d * DB ) readuint128_row (row []byte , pos uint32 ) uint128. Uint128 {
296+ retval := uint128 . From64 (0 )
295297 data := row [pos : pos + 16 ]
296298
297299 // little endian to big endian
298300 for i , j := 0 , len (data )- 1 ; i < j ; i , j = i + 1 , j - 1 {
299301 data [i ], data [j ] = data [j ], data [i ]
300302 }
301- retval .SetBytes (data )
303+ retval .PutBytes (data )
302304 return retval
303305}
304306
305307// read unsigned 128-bit integer
306- func (d * DB ) readuint128 (pos uint32 ) (* big. Int , error ) {
308+ func (d * DB ) readuint128 (pos uint32 ) (uint128. Uint128 , error ) {
307309 pos2 := int64 (pos )
308- retval := big . NewInt (0 )
310+ retval := uint128 . From64 (0 )
309311 data := make ([]byte , 16 )
310312 _ , err := d .f .ReadAt (data , pos2 - 1 )
311313 if err != nil {
312- return nil , err
314+ return uint128 . From64 ( 0 ) , err
313315 }
314316
315317 // little endian to big endian
316318 for i , j := 0 , len (data )- 1 ; i < j ; i , j = i + 1 , j - 1 {
317319 data [i ], data [j ] = data [j ], data [i ]
318320 }
319- retval .SetBytes (data )
321+ retval .PutBytes (data )
320322 return retval , nil
321323}
322324
@@ -331,7 +333,7 @@ func (d *DB) readstr(pos uint32) (string, error) {
331333 return "" , err
332334 }
333335 strlen := data [0 ]
334- retval = string (data [1 :(strlen + 1 )])
336+ retval = convertBytesToString (data [1 :(strlen + 1 )])
335337 return retval , nil
336338}
337339
@@ -365,11 +367,25 @@ func OpenDB(dbpath string) (*DB, error) {
365367func OpenDBWithReader (reader DBReader ) (* DB , error ) {
366368 var db = & DB {}
367369
368- max_ipv6_range .SetString ("340282366920938463463374607431768211455" , 10 )
369- from_6to4 .SetString ("42545680458834377588178886921629466624" , 10 )
370- to_6to4 .SetString ("42550872755692912415807417417958686719" , 10 )
371- from_teredo .SetString ("42540488161975842760550356425300246528" , 10 )
372- to_teredo .SetString ("42540488241204005274814694018844196863" , 10 )
370+ _max_ipv6_range := big .NewInt (0 )
371+ _max_ipv6_range .SetString ("340282366920938463463374607431768211455" , 10 )
372+ max_ipv6_range = uint128 .FromBig (_max_ipv6_range )
373+
374+ _from_6to4 := big .NewInt (0 )
375+ _from_6to4 .SetString ("42545680458834377588178886921629466624" , 10 )
376+ from_6to4 = uint128 .FromBig (_from_6to4 )
377+
378+ _to_6to4 := big .NewInt (0 )
379+ _to_6to4 .SetString ("42550872755692912415807417417958686719" , 10 )
380+ to_6to4 = uint128 .FromBig (_to_6to4 )
381+
382+ _from_teredo := big .NewInt (0 )
383+ _from_teredo .SetString ("42540488161975842760550356425300246528" , 10 )
384+ from_teredo = uint128 .FromBig (_from_teredo )
385+
386+ _to_teredo := big .NewInt (0 )
387+ _to_teredo .SetString ("42540488241204005274814694018844196863" , 10 )
388+ to_teredo = uint128 .FromBig (_to_teredo )
373389
374390 db .f = reader
375391
@@ -563,6 +579,13 @@ func handleError(rec IP2Locationrecord, err error) IP2Locationrecord {
563579 return rec
564580}
565581
582+ // convertBytesToString provides a no-copy []byte to string conversion.
583+ // This implementation is adopted by official strings.Builder.
584+ // Reference: https://github.com/golang/go/issues/25484
585+ func convertBytesToString (b []byte ) string {
586+ return * (* string )(unsafe .Pointer (& b ))
587+ }
588+
566589// Get_all will return all geolocation fields based on the queried IP address.
567590//
568591// Deprecated: No longer being updated.
@@ -854,9 +877,9 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
854877 var row []byte
855878 var fullrow []byte
856879 var readlen uint32
857- ipfrom := big . NewInt (0 )
858- ipto := big . NewInt (0 )
859- maxip := big . NewInt (0 )
880+ ipfrom := uint128 . From64 (0 )
881+ ipto := uint128 . From64 (0 )
882+ maxip := uint128 . From64 (0 )
860883
861884 if iptype == 4 {
862885 baseaddr = d .meta .ipv4databaseaddr
@@ -882,7 +905,7 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
882905 }
883906
884907 if ipno .Cmp (maxip ) >= 0 {
885- ipno .Sub (ipno , big . NewInt (1 ))
908+ ipno = ipno .Sub (uint128 . From64 (1 ))
886909 }
887910
888911 for low <= high {
@@ -898,10 +921,10 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
898921
899922 if iptype == 4 {
900923 ipfrom32 := d .readuint32_row (fullrow , 0 )
901- ipfrom = big . NewInt ( int64 (ipfrom32 ))
924+ ipfrom = uint128 . From64 ( uint64 (ipfrom32 ))
902925
903926 ipto32 := d .readuint32_row (fullrow , colsize )
904- ipto = big . NewInt ( int64 (ipto32 ))
927+ ipto = uint128 . From64 ( uint64 (ipto32 ))
905928 } else {
906929 ipfrom = d .readuint128_row (fullrow , 0 )
907930
0 commit comments