Merge branch 'mdsal-trace' from controller
[mdsal.git] / model / ietf / ietf-type-util / src / main / java / org / opendaylight / mdsal / model / ietf / util / Ipv6Utils.java
index d5f357d3d3b950bde3ac6972bfc686f2567045a0..5f2757083bddcb05070018d14b2199d5803ee157 100644 (file)
@@ -8,9 +8,9 @@
 package org.opendaylight.mdsal.model.ietf.util;
 
 import com.google.common.base.Preconditions;
-import com.google.common.net.InetAddresses;
-import java.net.Inet4Address;
-import java.net.InetAddress;
+import com.google.common.base.Verify;
+import java.util.Arrays;
+import javax.annotation.Nonnull;
 
 /**
  * IPv6 address parsing for ietf-inet-types ipv6-address and ipv6-prefix. This is an internal implementation
@@ -54,132 +54,85 @@ final class Ipv6Utils {
     /**
      * Convert Ipv6Address object to a valid Canonical v6 address in byte format
      *
-     * @param ipv6Address - v6 Address object
-     *
-     * FIXME: rovarga: this looks wrong
-     * @return - byte array of size 16. Last byte contains netmask
+     * @param bytes Byte array for output
+     * @param str String representation
+     * @param strLimit String offset which should not be processed
+     * @throws NullPointerException if ipv6address is null
      */
-   public static byte[] canonicalBinaryV6Address(final String ipv6Address) {
-       /*
-        * Do not modify this routine to take direct strings input!!!
-        * Key checks have been removed based on the assumption that
-        * the input is validated via regexps in Ipv6Prefix()
-        */
-
-       String [] address =  (ipv6Address).split("%");
-
-       int colonp;
-       char ch;
-       boolean saw_xdigit;
-
-       /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
-
-       int val;
-
-       char[] src = address[0].toCharArray();
-
-       byte[] dst = new byte[INADDR6SZ];
-
-       int src_length = src.length;
-
-       colonp = -1;
-       int i = 0, j = 0;
-
-       /* Leading :: requires some special handling. */
-
-       /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
-        * We will derive our code from BSD. Shakespear always sounds better
-        * in original Clingon. So does Dilbert.
-        */
-
-       if (src[i] == ':') {
-           Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
+    static void fillIpv6Bytes(final @Nonnull byte[] bytes, final String str, final int strLimit) {
+       // Leading :: requires some special handling.
+       int i = 0;
+       if (str.charAt(i) == ':') {
+           // Note ++i side-effect in check
+           Preconditions.checkArgument(str.charAt(++i) == ':', "Invalid v6 address '%s'", str);
        }
 
+       boolean haveVal = false;
+       int val = 0;
+       int colonp = -1;
+       int j = 0;
        int curtok = i;
-       saw_xdigit = false;
-
-
-       val = 0;
-       while (i < src_length) {
-           ch = src[i++];
-           int chval = Character.digit(ch, 16);
-
-           /* Business as usual - ipv6 address digit.
-            * We can remove all checks from the original BSD code because
-            * the regexp has already verified that we are not being fed
-            * anything bigger than 0xffff between the separators.
-            */
-
-           if (chval != -1) {
-               val <<= 4;
-               val |= chval;
-               saw_xdigit = true;
-               continue;
-           }
-
-           /* v6 separator */
+       while (i < strLimit) {
+           final char ch = str.charAt(i++);
 
+           // v6 separator
            if (ch == ':') {
                curtok = i;
-               if (!saw_xdigit) {
-                   /* no need to check separator position validity - regexp does that */
+               if (haveVal) {
+                   // removed overrun check - the regexp checks for valid data
+                   bytes[j++] = (byte) ((val >>> 8) & 0xff);
+                   bytes[j++] = (byte) (val & 0xff);
+                   haveVal = false;
+                   val = 0;
+               } else {
+                   // no need to check separator position validity - regexp does that
                    colonp = j;
-                   continue;
                }
 
-               /* removed overrun check - the regexp checks for valid data */
-
-               dst[j++] = (byte) ((val >>> 8) & 0xff);
-               dst[j++] = (byte) (val & 0xff);
-               saw_xdigit = false;
-               val = 0;
                continue;
            }
 
-           /* frankenstein - v4 attached to v6, mixed notation */
-
+           // frankenstein - v4 attached to v6, mixed notation
            if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
-
-               /* this has passed the regexp so it is fairly safe to parse it
-                * straight away. As v4 addresses do not suffer from the same
-                * defficiencies as the java v6 implementation we can invoke it
-                * straight away and be done with it
+               /*
+                * This has passed the regexp so it is fairly safe to parse it
+                * straight away. Use the Ipv4Utils for that.
                 */
-
-               Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
-
-               InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
-
-               Preconditions.checkArgument(_inet_form instanceof Inet4Address);
-               System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
+               Ipv4Utils.fillIpv4Bytes(bytes, j, str, curtok, strLimit);
                j += INADDR4SZ;
-
-               saw_xdigit = false;
+               haveVal = false;
                break;
            }
-           /* removed parser exit on invalid char - no need to do it, regexp checks it */
+
+           /*
+            * Business as usual - ipv6 address digit.
+            * We can remove all checks from the original BSD code because
+            * the regexp has already verified that we are not being fed
+            * anything bigger than 0xffff between the separators.
+            */
+           final int chval = AbstractIetfYangUtil.hexValue(ch);
+           val = (val << 4) | chval;
+           haveVal = true;
        }
-       if (saw_xdigit) {
-           Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
-           dst[j++] = (byte) ((val >> 8) & 0xff);
-           dst[j++] = (byte) (val & 0xff);
+
+       if (haveVal) {
+           Verify.verify(j + INT16SZ <= INADDR6SZ, "Overrun in parsing of '%s', should not occur", str);
+           bytes[j++] = (byte) ((val >> 8) & 0xff);
+           bytes[j++] = (byte) (val & 0xff);
        }
 
        if (colonp != -1) {
-           int n = j - colonp;
-
-           Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
-           for (i = 1; i <= n; i++) {
-               dst[INADDR6SZ - i] = dst[colonp + n - i];
-               dst[colonp + n - i] = 0;
-           }
-           j = INADDR6SZ;
+           Verify.verify(j != INADDR6SZ, "Overrun in parsing of '%s', should not occur", str);
+           expandZeros(bytes, colonp, j);
+       } else {
+           Verify.verify(j == INADDR6SZ, "Overrun in parsing of '%s', should not occur", str);
        }
-
-       Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
-
-       return dst;
    }
 
+   private static void expandZeros(final byte[] bytes, final int where, final int filledBytes) {
+       final int tailLength = filledBytes - where;
+       final int tailOffset = INADDR6SZ - tailLength;
+       System.arraycopy(bytes, where, bytes, tailOffset, tailLength);
+       Arrays.fill(bytes, where, tailOffset, (byte)0);
+    }
 }