ipv6 utils and testing
This commit is contained in:
parent
87d53b5018
commit
83fd149c59
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a Apache2.0-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package org.lionsoul.ip2region.xdb;
|
||||||
|
|
||||||
|
// IPv4 version implementation
|
||||||
|
// @Author Lion <chenxin619315@gmail.com>
|
||||||
|
// @Date 2025/09/10
|
||||||
|
|
||||||
|
public class IPv4 extends Version {
|
||||||
|
public IPv4() {
|
||||||
|
// segmentIndex: 4 + 4 + 2 + 4
|
||||||
|
super(4, "IPv4", 4, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int putBytes(byte[] buff, int offset, byte[] ip) {
|
||||||
|
// use the Little endian byte order to compatible with the old searcher implementation
|
||||||
|
buff[offset++] = ip[3];
|
||||||
|
buff[offset++] = ip[2];
|
||||||
|
buff[offset++] = ip[1];
|
||||||
|
buff[offset ] = ip[0];
|
||||||
|
return ip.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a Apache2.0-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package org.lionsoul.ip2region.xdb;
|
||||||
|
|
||||||
|
// IPv4 version implementation
|
||||||
|
// @Author Lion <chenxin619315@gmail.com>
|
||||||
|
// @Date 2025/09/10
|
||||||
|
|
||||||
|
public class IPv6 extends Version {
|
||||||
|
|
||||||
|
public IPv6() {
|
||||||
|
// segmentIndex: 16 + 16 + 2 + 4
|
||||||
|
super(6, "IPv6", 16, 38);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int putBytes(byte[] buff, int offset, byte[] ip) {
|
||||||
|
System.arraycopy(ip, 0, buff, offset, ip.length);
|
||||||
|
return ip.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a Apache2.0-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package org.lionsoul.ip2region.xdb;
|
||||||
|
|
||||||
|
// Little Endian basic data type decode and encode.
|
||||||
|
// @Author Lion <chenxin619315@gmail.com>
|
||||||
|
// @Date 2025/09/10
|
||||||
|
|
||||||
|
public class LittleEndian {
|
||||||
|
|
||||||
|
public final static int[] shiftIndex = {0, 8, 16, 24, 32, 40, 48, 56};
|
||||||
|
|
||||||
|
// put specified bytes to the buffer started from the offset
|
||||||
|
public static void put(final byte[] buff, int offset, long value, int bytes) {
|
||||||
|
if (bytes > 8) {
|
||||||
|
throw new IndexOutOfBoundsException("bytes should be <= 8");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes; i++) {
|
||||||
|
buff[offset++] = (byte)((value >>> shiftIndex[i]) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// put an uint32 (4 bytes long) to the buffer from the offset
|
||||||
|
public static void putUint32(final byte[] buff, int offset, long value) {
|
||||||
|
buff[offset++] = (byte) (value & 0xFF);
|
||||||
|
buff[offset++] = (byte) ((value >> 8) & 0xFF);
|
||||||
|
buff[offset++] = (byte) ((value >> 16) & 0xFF);
|
||||||
|
buff[offset ] = (byte) ((value >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// put a 2-bytes int to the buffer from the specified offset
|
||||||
|
public static void putInt2(final byte[] buff, int offset, int value) {
|
||||||
|
buff[offset++] = (byte) (value & 0xFF);
|
||||||
|
buff[offset ] = (byte) ((value >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get an uint32 from a byte array from the specified offset
|
||||||
|
public static long getUint32(final byte[] buff, int offset) {
|
||||||
|
return (
|
||||||
|
((buff[offset++] & 0x000000FFL)) |
|
||||||
|
((buff[offset++] << 8) & 0x0000FF00L) |
|
||||||
|
((buff[offset++] << 16) & 0x00FF0000L) |
|
||||||
|
((buff[offset ] << 24) & 0xFF000000L)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get an 2 bytes int from a byte array from the specified offset
|
||||||
|
public static int getInt2(final byte[] buff, int offset) {
|
||||||
|
return (
|
||||||
|
((buff[offset++]) & 0x000000FF) |
|
||||||
|
((buff[offset ] << 8) & 0x0000FF00)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,51 @@ package org.lionsoul.ip2region.xdb;
|
||||||
|
|
||||||
public class Util
|
public class Util
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// compare two byte ip
|
||||||
|
// Returns: -1 if ip1 < ip2, 0 if ip1 == ip2, 1 if ip1 > ip2
|
||||||
|
public static int ipCompare(byte[] ip1, byte[] ip2) {
|
||||||
|
for (int i = 0; i < ip1.length; i++) {
|
||||||
|
if (ip1[i] < ip2[i]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip1[i] > ip2[i]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ipAddOne(byte[] ip) {
|
||||||
|
final byte[] r = new byte[ip.length];
|
||||||
|
System.arraycopy(ip, 0, r, 0, ip.length);
|
||||||
|
for (int i = ip.length - 1; i >= 0; i--) {
|
||||||
|
r[i]++;
|
||||||
|
if (r[i] != 0) { // No overflow
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ipSubOne(byte[] ip) {
|
||||||
|
final byte[] r = new byte[ip.length];
|
||||||
|
System.arraycopy(ip, 0, r, 0, ip.length);
|
||||||
|
for (int i = ip.length - 1; i >= 0; i--) {
|
||||||
|
if (r[i] != 0) { // No borrow needed
|
||||||
|
r[i]--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r[i] = (byte) 0xFF; // borrow from the next byte
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// write specified bytes into a byte array start from offset
|
// write specified bytes into a byte array start from offset
|
||||||
public static void write( byte[] b, int offset, long v, int bytes) {
|
public static void write( byte[] b, int offset, long v, int bytes) {
|
||||||
for ( int i = 0; i < bytes; i++ ) {
|
for ( int i = 0; i < bytes; i++ ) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2025 The Ip2Region Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a Apache2.0-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package org.lionsoul.ip2region.xdb;
|
||||||
|
|
||||||
|
// IP version abstract manager (IPv4 & IPv6)
|
||||||
|
// @Author Lion <chenxin619315@gmail.com>
|
||||||
|
// @Date 2025/09/10
|
||||||
|
|
||||||
|
public abstract class Version {
|
||||||
|
public static final int IPv4VersionNo = 4;
|
||||||
|
public static final int IPv6VersionNo = 6;
|
||||||
|
|
||||||
|
public static final IPv4 IPv4 = new IPv4();
|
||||||
|
public static final IPv6 IPv6 = new IPv6();
|
||||||
|
|
||||||
|
// version id and name
|
||||||
|
public final int id;
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
// the numbers of bytes for one IP
|
||||||
|
public final int bytes;
|
||||||
|
|
||||||
|
// segment index size (bytes)
|
||||||
|
public final int segmentIndexSize;
|
||||||
|
|
||||||
|
public Version(int id, String name, int bytes, int segmentIndexSize) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.segmentIndexSize = segmentIndexSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the specified IP bytes to the specified buffer
|
||||||
|
public abstract int putBytes(byte[] buff, int offset, byte[] ip);
|
||||||
|
|
||||||
|
// compare the two IPs with the current version.
|
||||||
|
// Returns: -1 if ip1 < ip2, 0 if ip1 == ip2, 1 if ip1 > ip2
|
||||||
|
public int ipCompare(byte[] ip1, byte[] ip2) {
|
||||||
|
return Util.ipCompare(ip1, ip2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the version from an name
|
||||||
|
public static final Version fromName(String name) throws Exception {
|
||||||
|
final String n = name.toUpperCase();
|
||||||
|
if (n.equals("V4") || n.equals("IPV4")) {
|
||||||
|
return IPv4;
|
||||||
|
} else if (n.equals("V6") || n.equals("IPV6")) {
|
||||||
|
return IPv6;
|
||||||
|
} else {
|
||||||
|
throw new Exception("invalid version name `"+name+"`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return String.format("{Id:%d, Name:%s, Bytes:%d, IndexSize: %d}", id, name, bytes, segmentIndexSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.lionsoul.ip2region.xdb;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class LittleEndianTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAll() {
|
||||||
|
final byte[] buff = new byte[14];
|
||||||
|
|
||||||
|
// encode
|
||||||
|
// do the put
|
||||||
|
LittleEndian.put(buff, 0, 1L, 4);
|
||||||
|
LittleEndian.put(buff, 4, 2L, 4);
|
||||||
|
|
||||||
|
// putUint32
|
||||||
|
LittleEndian.putInt2(buff, 8, 24);
|
||||||
|
LittleEndian.putUint32(buff, 10, 1024L);
|
||||||
|
|
||||||
|
// decode
|
||||||
|
assertEquals(LittleEndian.getUint32(buff, 0), 1);
|
||||||
|
assertEquals(LittleEndian.getUint32(buff, 4), 2);
|
||||||
|
assertEquals(LittleEndian.getInt2(buff, 8), 24);
|
||||||
|
assertEquals(LittleEndian.getUint32(buff, 10), 1024);
|
||||||
|
|
||||||
|
System.out.printf("uint32(buff, 0): %d\n", LittleEndian.getUint32(buff, 0));
|
||||||
|
System.out.printf("uint32(buff, 4): %d\n", LittleEndian.getUint32(buff, 4));
|
||||||
|
System.out.printf("int2(buff, 8): %d\n", LittleEndian.getInt2(buff, 8));
|
||||||
|
System.out.printf("uint32(buff, 10): %d\n", LittleEndian.getUint32(buff, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.lionsoul.ip2region.xdb;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class VersionTest {
|
||||||
|
@Test
|
||||||
|
public void testFromName() throws Exception {
|
||||||
|
final String[] vers = new String[]{"IPv4", "IPv6"};
|
||||||
|
final Version v4 = Version.fromName(vers[0]);
|
||||||
|
assertEquals(v4.name, vers[0]);
|
||||||
|
final Version v6 = Version.fromName(vers[1]);
|
||||||
|
assertEquals(v6.name, vers[1]);
|
||||||
|
|
||||||
|
System.out.printf("v4: %s\n", v4);
|
||||||
|
System.out.printf("v6: %s\n", v6);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue