All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.projectfloodlight.openflow.util.HexString Maven / Gradle / Ivy

Go to download

OpenFlowJ API supporting OpenFlow versions 1.0 through 1.5.1, generated by LoxiGen

There is a newer version: 3.6.605
Show newest version
package org.projectfloodlight.openflow.util;

import io.netty.util.internal.EmptyArrays;

/** Utility method to convert hexadecimal string from/to longs and byte arrays.
 *
 * @author Andreas Wundsam {@literal <}[email protected]{@literal >}
 */
public final class HexString {

    private HexString() {}

    /* ================================================================================
     * Implementation note:
     * These implementations are optimized for small-O efficiency and thus rather ugly.
     *
     * When making changes, make sure *every line* is covered by a unit test.
     *
     * Do not use this as a blue print for normal code.
     * ================================================================================
     */

    private final static char[] CHARS =
        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    /**
     * Convert a string of bytes to a ':' separated hex string
     *
     * @param bytes the byte[] to convert
     * @return "0f:ca:fe:de:ad:be:ef"
     */
    public static String toHexString(final byte[] bytes) {
        int lenBytes = bytes.length;
        if (lenBytes == 0) {
            return "";
        }
        char arr[] = new char[lenBytes * 2 + (lenBytes -1)];

        int charPos = 0;
        int i = 0;

        for (;;) {
            arr[charPos++] = CHARS[ (bytes[i] >>> 4) & 0xF ];
            arr[charPos++] = CHARS[ bytes[i] & 0xF ];
            if (++i >= lenBytes) {
                break;
            }
            arr[charPos++] = ':';
        }

        return new String(arr, 0, arr.length);
    }

    public static String toHexString(long val, final int padTo) {
        int valBytes = (64 - Long.numberOfLeadingZeros(val) + 7)/8;
        int lenBytes = valBytes > padTo ? valBytes : padTo;

        char arr[] = new char[lenBytes * 2 + (lenBytes -1)];

        // fill char array from the last position, shifting val by 4 bits
        for (int charPos = arr.length - 1; charPos >= 0; charPos--) {
            if ((charPos + 1) % 3 == 0) {
                // every third char is a colon
                arr[charPos] = ':';
            } else {
                arr[charPos] = CHARS[((int) val) & 0xF];
                val >>>= 4;
            }
        }
        return new String(arr, 0, arr.length);
    }

    public static String toHexString(final long val) {
        return toHexString(val, 8);
    }


    /** Deprecated version of {@link #toBytes(String)}.
     *
     * @throws NumberFormatException upon values parse error
     * @param values the hexstring to parse into a byte[]
     * @return a byte[] representing the hexstring
     * {@link Deprecated} because of inconsistent naming
     */
    @Deprecated
    public static byte[] fromHexString(final String values) throws NumberFormatException {
        return toBytes(values);
    }

    /** state constants for toBytes */
    /** expecting first digit */
    private final static int FIRST_DIGIT = 1;
    /** expecting second digit or colon */
    private static final int SECOND_DIGIT_OR_COLON = 2;
    /** expecting colon */
    private static final int COLON = 3;
    /** save byte and move back to FIRST_DIGIT */
    private static final int SAVE_BYTE = 4;

    /**
     * Convert a string of hex values into a string of bytes.
     *
     * @param values
     *            "0f:ca:fe:de:ad:be:ef"
     * @return [15, 5 ,2, 5, 17]
     * @throws NumberFormatException
     *             If the string can not be parsed
     */
    public static byte[] toBytes(final String values) throws NumberFormatException {
        int start = 0;
        int len = values.length();

        if (len == 0) {
            return EmptyArrays.EMPTY_BYTES;
        }

        int numColons = 0;
        for (int i=0; i < len; i++) {
            if (values.charAt(i) == ':') {
                numColons++;
            }
        }

        byte[] res = new byte[numColons+1];
        int pos = 0;

        int state = FIRST_DIGIT;

        byte b = 0;
        while (start < len) {
            char c = values.charAt(start++);
            switch (state) {
                case FIRST_DIGIT:
                    int digit = Character.digit(c, 16);
                    if(digit < 0) {
                        throw new NumberFormatException("Invalid char at index " + start + ": " + values);
                    }
                    b = (byte) digit;
                    state = start < len ? SECOND_DIGIT_OR_COLON : SAVE_BYTE;
                    break;
                case SECOND_DIGIT_OR_COLON:
                    if(c != ':') {
                        int digit2 = Character.digit(c, 16);
                        if(digit2 < 0) {
                            throw new NumberFormatException("Invalid char at index " + start + ": " + values);
                        }
                        b =  (byte) ((b<<4) | digit2);
                        state = start < len ? COLON : SAVE_BYTE;
                    } else {
                        state = SAVE_BYTE;
                    }
                    break;
                case COLON:
                    if(c != ':') {
                        throw new NumberFormatException("Separator expected at index " + start + ": " + values);
                    }
                    state = SAVE_BYTE;
                    break;
                default:
                    throw new IllegalStateException("Should not be in state " + state);
            }
            if (state == SAVE_BYTE) {
                res[pos++] = b;
                b = 0;
                state = FIRST_DIGIT;
            }
        }
        if (pos != res.length) {
            // detects a mal-formed input string, e.g., "01:02:"
            throw new NumberFormatException("Invalid hex string: " + values);
        }

        return res;
    }

    public static long toLong(String value) throws NumberFormatException {
        int shift = 0;
        long result = 0L;

        int sinceLastSeparator = 0;
        for (int charPos=value.length() - 1; charPos >= 0; charPos--) {
            char c = value.charAt(charPos);
            if (c == ':') {
                if (sinceLastSeparator == 0) {
                    throw new NumberFormatException("Expected hex digit at index " + charPos +": " + value);
                } else if(sinceLastSeparator == 1) {
                    shift += 4;
                }
                sinceLastSeparator = 0;
            } else {
                int digit = Character.digit(c, 16);
                if (digit < 0) {
                    throw new NumberFormatException("Invalid hex digit at index " + charPos +": " + value);
                }
                result |= ((long) digit) << shift;
                shift +=4;
                sinceLastSeparator++;
                if (sinceLastSeparator > 2) {
                    throw new NumberFormatException("Expected colon at index " + charPos +": " + value);
                }
            }
            if (shift > 64) {
                throw new NumberFormatException("Too many bytes in hex string to convert to long: " + value);
            }
        }
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy