From 697b46bb2e3d24ecc098191fcd606b8ef67c3c8f Mon Sep 17 00:00:00 2001 From: lion Date: Wed, 10 Sep 2025 22:46:14 +0800 Subject: [PATCH] ip util functions and its unit test --- .../xdb/InvalidInetAddressException.java | 9 +++ .../java/org/lionsoul/ip2region/xdb/Util.java | 58 ++++++++++++-- .../org/lionsoul/ip2region/xdb/UtilTest.java | 80 +++++++++++++++++++ 3 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 maker/java/src/main/java/org/lionsoul/ip2region/xdb/InvalidInetAddressException.java create mode 100644 maker/java/src/test/java/org/lionsoul/ip2region/xdb/UtilTest.java diff --git a/maker/java/src/main/java/org/lionsoul/ip2region/xdb/InvalidInetAddressException.java b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/InvalidInetAddressException.java new file mode 100644 index 0000000..6e32558 --- /dev/null +++ b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/InvalidInetAddressException.java @@ -0,0 +1,9 @@ +package org.lionsoul.ip2region.xdb; + +public class InvalidInetAddressException extends Exception { + + public InvalidInetAddressException(String str) { + super(str); + } + +} diff --git a/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Util.java b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Util.java index 5ebbb22..ba03c0f 100644 --- a/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Util.java +++ b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Util.java @@ -7,18 +7,61 @@ package org.lionsoul.ip2region.xdb; +import java.net.InetAddress; +import java.net.UnknownHostException; + public class Util { + // parse the specified IP address and return its bytes. + // returns: byte[4] for IPv6 and byte[16] for IPv6 and the bytes should be in Big endian order. + public static byte[] parseIP(String ip) throws InvalidInetAddressException { + try { + return InetAddress.getByName(ip).getAddress(); + } catch (UnknownHostException e) { + throw new InvalidInetAddressException("invalid ip address `"+ip+"`"); + } + } + + // print the ip in bytes + public static String ipToString(final byte[] ip) throws InvalidInetAddressException { + if (ip.length != 4 && ip.length != 16) { + throw new InvalidInetAddressException("invalid ip address length `"+ip.length+"`"); + } + + try { + return InetAddress.getByAddress(ip).getHostAddress(); + } catch (UnknownHostException e) { + throw new InvalidInetAddressException("invalid ip address `"+ipArrayString(ip)+"`"); + } + } + + // implode the byte[] ip with its byte value. + public static String ipArrayString(byte[] ip) { + final StringBuffer sb = new StringBuffer(); + sb.append("["); + for (int i = 0; i < ip.length; i++) { + if (i > 0) { + sb.append(','); + } + sb.append((ip[i] & 0xFF)); + } + sb.append("]"); + return sb.toString(); + } + // 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]) { + // covert the byte to int to sure the uint8 attribute + final int i1 = (int)(ip1[i] & 0xFF); + final int i2 = (int)(ip2[i] & 0xFF); + if (i1 < i2) { return -1; } - if (ip1[i] > ip2[i]) { + if (i1 > i2) { return 1; } } @@ -30,10 +73,13 @@ public class Util 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 + final int v = (int)(r[i] & 0xFF); + if (v < 255) { // No overflow + r[i]++; break; } + + r[i] = 0; } return r; @@ -43,10 +89,12 @@ public class Util 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 + final int v = (int)(r[i] & 0xFF); + if (v > 0) { // No borrow needed r[i]--; break; } + r[i] = (byte) 0xFF; // borrow from the next byte } diff --git a/maker/java/src/test/java/org/lionsoul/ip2region/xdb/UtilTest.java b/maker/java/src/test/java/org/lionsoul/ip2region/xdb/UtilTest.java new file mode 100644 index 0000000..d3ef7c9 --- /dev/null +++ b/maker/java/src/test/java/org/lionsoul/ip2region/xdb/UtilTest.java @@ -0,0 +1,80 @@ +package org.lionsoul.ip2region.xdb; + +import java.net.UnknownHostException; + +import org.junit.Test; + +public class UtilTest { + + public static final Log log = Log.getLogger(UtilTest.class).setLevel(Log.DEBUG); + + @Test + public void testCheckIP() throws InvalidInetAddressException { + final String[] ips = new String[]{ + "192.168.1.102", + "219.133.111.87", + "::", + "3000::", + "::1001:ffff", + "2001:2:0:ffff:ffff:ffff:ffff:ffff", + "::ffff:114.114.114.114" + }; + + for (String ip : ips) { + final byte[] ipBytes = Util.parseIP(ip); + log.debugf("%s(v=%s) => %s", ip, Util.ipArrayString(ipBytes), Util.ipToString(ipBytes)); + } + } + + @Test + public void testIpCompare() throws InvalidInetAddressException { + final String[][] ipPairs = new String[][]{ + {"1.0.0.0", "1.0.0.1"}, + {"192.168.1.101", "192.168.1.90"}, + {"219.133.111.87", "114.114.114.114"}, + {"2000::", "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"}, + {"2001:4:112::", "2001:4:112:ffff:ffff:ffff:ffff:ffff"}, + {"ffff::", "2001:4:ffff:ffff:ffff:ffff:ffff:ffff"} + }; + + for (String[] ips : ipPairs) { + final byte[] ip1 = Util.parseIP(ips[0]); + final byte[] ip2 = Util.parseIP(ips[1]); + log.debugf("compare(%s, %s): %d", ips[0], ips[1], Util.ipCompare(ip1, ip2)); + } + } + + @Test + public void testIpAddOne() throws InvalidInetAddressException { + final String[] ips = new String[] { + "1.0.0.0", + "192.168.1.255", + "2000::", + "255.255.255.254", + "0.0.0.255", + "0.255.255.255", + "1.1.255.255" + }; + for (String ip : ips) { + final byte[] ipBytes = Util.parseIP(ip); + log.debugf("ipAddOne(%s): %s", ip, Util.ipToString(Util.ipAddOne(ipBytes))); + } + } + + @Test + public void testIpSubOne() throws InvalidInetAddressException { + final String[] ips = new String[] { + "192.168.1.255", + "1.0.0.1", + "1.0.0.0", + "2.0.0.0", + "2000::", + "ffff::", + "1::1", + }; + for (String ip : ips) { + final byte[] ipBytes = Util.parseIP(ip); + log.debugf("ipSubOne(%s): %s", ip, Util.ipToString(Util.ipSubOne(ipBytes))); + } + } +}