    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.lang3;
    018
    019import java.util.UUID;
    020
    021/**
    022 * Static methods to convert a type into another, with endianness and bit ordering awareness.
    023 *
    024 * <p>
    025 * The methods names follow a naming rule:<br>
    026 * {@code <source type>[source endianness][source bit ordering]To<destination type>[destination endianness][destination bit ordering]}
    027 * </p>
    028 * <p>
    029 * Source/destination type fields is one of the following:
    030 * </p>
    031 * <ul>
    032 * <li>binary: an array of booleans</li>
    033 * <li>byte or byteArray</li>
    034 * <li>int or intArray</li>
    035 * <li>long or longArray</li>
    036 * <li>hex: a String containing hexadecimal digits (lowercase in destination)</li>
    037 * <li>hexDigit: a Char containing a hexadecimal digit (lowercase in destination)</li>
    038 * <li>uuid</li>
    039 * </ul>
    040 * <p>
    041 * Endianness field: little-endian is the default, in this case the field is absent. In case of
    042 * big-endian, the field is "Be".<br> Bit ordering: Lsb0 is the default, in this case the field
    043 * is absent. In case of Msb0, the field is "Msb0".
    044 * </p>
    045 * <p>
    046 * Example: intBeMsb0ToHex convert an int with big-endian byte order and Msb0 bit order into its
    047 * hexadecimal string representation
    048 * </p>
    049 * <p>
    050 * Most of the methods provide only default encoding for destination, this limits the number of
    051 * ways to do one thing. Unless you are dealing with data from/to outside of the JVM platform,
    052 * you should not need to use "Be" and "Msb0" methods.
    053 * </p>
    054 * <p>
    055 * Development status: work on going, only a part of the little-endian, Lsb0 methods implemented
    056 * so far.
    057 * </p>
    058 *
    059 * @since 3.2
    060 */
    061public class Conversion {
    062
    063    private static final boolean[] TTTT = {true, true, true, true};
    064    private static final boolean[] FTTT = {false, true, true, true};
    065    private static final boolean[] TFTT = {true, false, true, true};
    066    private static final boolean[] FFTT = {false, false, true, true};
    067    private static final boolean[] TTFT = {true, true, false, true};
    068    private static final boolean[] FTFT = {false, true, false, true};
    069    private static final boolean[] TFFT = {true, false, false, true};
    070    private static final boolean[] FFFT = {false, false, false, true};
    071    private static final boolean[] TTTF = {true, true, true, false};
    072    private static final boolean[] FTTF = {false, true, true, false};
    073    private static final boolean[] TFTF = {true, false, true, false};
    074    private static final boolean[] FFTF = {false, false, true, false};
    075    private static final boolean[] TTFF = {true, true, false, false};
    076    private static final boolean[] FTFF = {false, true, false, false};
    077    private static final boolean[] TFFF = {true, false, false, false};
    078    private static final boolean[] FFFF = {false, false, false, false};
    079
    080    /**
    081     * Converts the first 4 bits of a binary (represented as boolean array) in big-endian Msb0
    082     * bit ordering to a hexadecimal digit.
    083     *
    084     * <p>
    085     * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0) is converted
    086     * to '4'
    087     * </p>
    088     *
    089     * @param src the binary to convert
    090     * @return a hexadecimal digit representing the selected bits
    091     * @throws IllegalArgumentException if {@code src} is empty
    092     * @throws NullPointerException if {@code src} is {@code null}
    093     */
    094    public static char binaryBeMsb0ToHexDigit(final boolean[] src) {
    095        return binaryBeMsb0ToHexDigit(src, 0);
    096    }
    097
    098    /**
    099     * Converts a binary (represented as boolean array) in big-endian Msb0 bit ordering to a
    100     * hexadecimal digit.
    101     *
    102     * <p>
    103     * (1, 0, 0, 0) with srcPos = 0 is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0,
    104     * 0, 0, 0, 1, 0, 1, 0, 0) with srcPos = 2 is converted to '5'
    105     * </p>
    106     *
    107     * @param src the binary to convert
    108     * @param srcPos the position of the lsb to start the conversion
    109     * @return a hexadecimal digit representing the selected bits
    110     * @throws IllegalArgumentException if {@code src} is empty
    111     * @throws NullPointerException if {@code src} is {@code null}
    112     * @throws IndexOutOfBoundsException if {@code srcPos} is outside the array.
    113     */
    114    public static char binaryBeMsb0ToHexDigit(final boolean[] src, final int srcPos) {
    115        // JDK 9: Objects.checkIndex(int index, int length)
    116        if (Integer.compareUnsigned(srcPos, src.length) >= 0) {
    117            // Throw the correct exception
    118            if (src.length == 0) {
    119                throw new IllegalArgumentException("Cannot convert an empty array.");
    120            }
    121            throw new IndexOutOfBoundsException(srcPos + " is not within array length " + src.length);
    122        }
    123        // Little-endian bit 0 position
    124        final int pos = src.length - 1 - srcPos;
    125        if (3 <= pos && src[pos - 3]) {
    126            if (src[pos - 2]) {
    127                if (src[pos - 1]) {
    128                    return src[pos] ? 'f' : 'e';
    129                }
    130                return src[pos] ? 'd' : 'c';
    131            }
    132            if (src[pos - 1]) {
    133                return src[pos] ? 'b' : 'a';
    134            }
    135            return src[pos] ? '9' : '8';
    136        }
    137        if (2 <= pos && src[pos - 2]) {
    138            if (src[pos - 1]) {
    139                return src[pos] ? '7' : '6';
    140            }
    141            return src[pos] ? '5' : '4';
    142        }
    143        if (1 <= pos && src[pos - 1]) {
    144            return src[pos] ? '3' : '2';
    145        }
    146        return src[pos] ? '1' : '0';
    147    }
    148
    149    /**
    150     * Converts binary (represented as boolean array) into a byte using the default (little
    151     * endian, Lsb0) byte and bit ordering.
    152     *
    153     * @param src the binary to convert
    154     * @param srcPos the position in {@code src}, in boolean unit, from where to start the
    155     *            conversion
    156     * @param dstInit initial value of the destination byte
    157     * @param dstPos the position of the lsb, in bits, in the result byte
    158     * @param nBools the number of booleans to convert
    159     * @return a byte containing the selected bits
    160     * @throws NullPointerException if {@code src} is {@code null}
    161     * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 8}
    162     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
    163     */
    164    public static byte binaryToByte(final boolean[] src, final int srcPos, final byte dstInit, final int dstPos,
    165            final int nBools) {
    166        if (src.length == 0 && srcPos == 0 || 0 == nBools) {
    167            return dstInit;
    168        }
    169        if (nBools - 1 + dstPos >= 8) {
    170            throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 8");
    171        }
    172        byte out = dstInit;
    173        for (int i = 0; i < nBools; i++) {
    174            final int shift = i + dstPos;
    175            final int bits = (src[i + srcPos] ? 1 : 0) << shift;
    176            final int mask = 0x1 << shift;
    177            out = (byte) (out & ~mask | bits);
    178        }
    179        return out;
    180    }
    181
    182    /**
    183     * Converts binary (represented as boolean array) to a hexadecimal digit using the default
    184     * (Lsb0) bit ordering.
    185     *
    186     * <p>
    187     * (1, 0, 0, 0) is converted as follow: '1'
    188     * </p>
    189     *
    190     * @param src the binary to convert
    191     * @return a hexadecimal digit representing the selected bits
    192     * @throws IllegalArgumentException if {@code src} is empty
    193     * @throws NullPointerException if {@code src} is {@code null}
    194     */
    195    public static char binaryToHexDigit(final boolean[] src) {
    196        return binaryToHexDigit(src, 0);
    197    }
    198
    199    /**
    200     * Converts binary (represented as boolean array) to a hexadecimal digit using the default
    201     * (Lsb0) bit ordering.
    202     *
    203     * <p>
    204     * (1, 0, 0, 0) is converted as follow: '1'
    205     * </p>
    206     *
    207     * @param src the binary to convert
    208     * @param srcPos the position of the lsb to start the conversion
    209     * @return a hexadecimal digit representing the selected bits
    210     * @throws IllegalArgumentException if {@code src} is empty
    211     * @throws NullPointerException if {@code src} is {@code null}
    212     */
    213    public static char binaryToHexDigit(final boolean[] src, final int srcPos) {
    214        if (src.length == 0) {
    215            throw new IllegalArgumentException("Cannot convert an empty array.");
    216        }
    217        if (src.length > srcPos + 3 && src[srcPos + 3]) {
    218            if (src[srcPos + 2]) {
    219                if (src[srcPos + 1]) {
    220                    return src[srcPos] ? 'f' : 'e';
    221                }
    222                return src[srcPos] ? 'd' : 'c';
    223            }
    224            if (src[srcPos + 1]) {
    225                return src[srcPos] ? 'b' : 'a';
    226            }
    227            return src[srcPos] ? '9' : '8';
    228        }
    229        if (src.length > srcPos + 2 && src[srcPos + 2]) {
    230            if (src[srcPos + 1]) {
    231                return src[srcPos] ? '7' : '6';
    232            }
    233            return src[srcPos] ? '5' : '4';
    234        }
    235        if (src.length > srcPos + 1 && src[srcPos + 1]) {
    236            return src[srcPos] ? '3' : '2';
    237        }
    238        return src[srcPos] ? '1' : '0';
    239    }
    240
    241    /**
    242     * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit
    243     * ordering.
    244     *
    245     * <p>
    246     * (1, 0, 0, 0) is converted as follow: '8'
    247     * </p>
    248     *
    249     * @param src the binary to convert
    250     * @return a hexadecimal digit representing the selected bits
    251     * @throws IllegalArgumentException if {@code src} is empty, {@code src.length < 4} or
    252     *             {@code src.length > 8}
    253     * @throws NullPointerException if {@code src} is {@code null}
    254     */
    255    public static char binaryToHexDigitMsb0_4bits(final boolean[] src) {
    256        return binaryToHexDigitMsb0_4bits(src, 0);
    257    }
    258
    259    /**
    260     * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit
    261     * ordering.
    262     *
    263     * <p>
    264     * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 1, 1, 0, 1, 0) with srcPos = 3 is converted
    265     * to 'D'
    266     * </p>
    267     *
    268     * @param src the binary to convert
    269     * @param srcPos the position of the lsb to start the conversion
    270     * @return a hexadecimal digit representing the selected bits
    271     * @throws IllegalArgumentException if {@code src} is empty, {@code src.length > 8} or
    272     *             {@code src.length - srcPos < 4}
    273     * @throws NullPointerException if {@code src} is {@code null}
    274     */
    275    public static char binaryToHexDigitMsb0_4bits(final boolean[] src, final int srcPos) {
    276        if (src.length > 8) {
    277            throw new IllegalArgumentException("src.length>8: src.length=" + src.length);
    278        }
    279        if (src.length - srcPos < 4) {
    280            throw new IllegalArgumentException("src.length-srcPos<4: src.length=" + src.length + ", srcPos=" + srcPos);
    281        }
    282        if (src[srcPos + 3]) {
    283            if (src[srcPos + 2]) {
    284                if (src[srcPos + 1]) {
    285                    return src[srcPos] ? 'f' : '7';
    286                }
    287                return src[srcPos] ? 'b' : '3';
    288            }
    289            if (src[srcPos + 1]) {
    290                return src[srcPos] ? 'd' : '5';
    291            }
    292            return src[srcPos] ? '9' : '1';
    293        }
    294        if (src[srcPos + 2]) {
    295            if (src[srcPos + 1]) {
    296                return src[srcPos] ? 'e' : '6';
    297            }
    298            return src[srcPos] ? 'a' : '2';
    299        }
    300        if (src[srcPos + 1]) {
    301            return src[srcPos] ? 'c' : '4';
    302        }
    303        return src[srcPos] ? '8' : '0';
    304    }
    305
    306    /**
    307     * Converts binary (represented as boolean array) into an int using the default (little
    308     * endian, Lsb0) byte and bit ordering.
    309     *
    310     * @param src the binary to convert
    311     * @param srcPos the position in {@code src}, in boolean unit, from where to start the
    312     *            conversion
    313     * @param dstInit initial value of the destination int
    314     * @param dstPos the position of the lsb, in bits, in the result int
    315     * @param nBools the number of booleans to convert
    316     * @return an int containing the selected bits
    317     * @throws NullPointerException if {@code src} is {@code null}
    318     * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 32}
    319     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
    320     */
    321    public static int binaryToInt(final boolean[] src, final int srcPos, final int dstInit, final int dstPos,
    322            final int nBools) {
    323        if (src.length == 0 && srcPos == 0 || 0 == nBools) {
    324            return dstInit;
    325        }
    326        if (nBools - 1 + dstPos >= 32) {
    327            throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 32");
    328        }
    329        int out = dstInit;
    330        for (int i = 0; i < nBools; i++) {
    331            final int shift = i + dstPos;
    332            final int bits = (src[i + srcPos] ? 1 : 0) << shift;
    333            final int mask = 0x1 << shift;
    334            out = out & ~mask | bits;
    335        }
    336        return out;
    337    }
    338
    339    /**
    340     * Converts binary (represented as boolean array) into a long using the default (little
    341     * endian, Lsb0) byte and bit ordering.
    342     *
    343     * @param src the binary to convert
    344     * @param srcPos the position in {@code src}, in boolean unit, from where to start the
    345     *            conversion
    346     * @param dstInit initial value of the destination long
    347     * @param dstPos the position of the lsb, in bits, in the result long
    348     * @param nBools the number of booleans to convert
    349     * @return a long containing the selected bits
    350     * @throws NullPointerException if {@code src} is {@code null}
    351     * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 64}
    352     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
    353     */
    354    public static long binaryToLong(final boolean[] src, final int srcPos, final long dstInit, final int dstPos,
    355            final int nBools) {
    356        if (src.length == 0 && srcPos == 0 || 0 == nBools) {
    357            return dstInit;
    358        }
    359        if (nBools - 1 + dstPos >= 64) {
    360            throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 64");
    361        }
    362        long out = dstInit;
    363        for (int i = 0; i < nBools; i++) {
    364            final int shift = i + dstPos;
    365            final long bits = (src[i + srcPos] ? 1L : 0) << shift;
    366            final long mask = 0x1L << shift;
    367            out = out & ~mask | bits;
    368        }
    369        return out;
    370    }
    371
    372    /**
    373     * Converts binary (represented as boolean array) into a short using the default (little
    374     * endian, Lsb0) byte and bit ordering.
    375     *
    376     * @param src the binary to convert
    377     * @param srcPos the position in {@code src}, in boolean unit, from where to start the
    378     *            conversion
    379     * @param dstInit initial value of the destination short
    380     * @param dstPos the position of the lsb, in bits, in the result short
    381     * @param nBools the number of booleans to convert
    382     * @return a short containing the selected bits
    383     * @throws NullPointerException if {@code src} is {@code null}
    384     * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 16}
    385     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
    386     */
    387    public static short binaryToShort(final boolean[] src, final int srcPos, final short dstInit, final int dstPos,
    388            final int nBools) {
    389        if (src.length == 0 && srcPos == 0 || 0 == nBools) {
    390            return dstInit;
    391        }
    392        if (nBools - 1 + dstPos >= 16) {
    393            throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 16");
    394        }
    395        short out = dstInit;
    396        for (int i = 0; i < nBools; i++) {
    397            final int shift = i + dstPos;
    398            final int bits = (src[i + srcPos] ? 1 : 0) << shift;
    399            final int mask = 0x1 << shift;
    400            out = (short) (out & ~mask | bits);
    401        }
    402        return out;
    403    }
    404
    405    /**
    406     * Converts an array of byte into an int using the default (little-endian, Lsb0) byte and bit
    407     * ordering.
    408     *
    409     * @param src the byte array to convert
    410     * @param srcPos the position in {@code src}, in byte unit, from where to start the
    411     *            conversion
    412     * @param dstInit initial value of the destination int
    413     * @param dstPos the position of the lsb, in bits, in the result int
    414     * @param nBytes the number of bytes to convert
    415     * @return an int containing the selected bits
    416     * @throws NullPointerException if {@code src} is {@code null}
    417     * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 32}
    418     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
    419     */
    420    public static int byteArrayToInt(final byte[] src, final int srcPos, final int dstInit, final int dstPos,
    421            final int nBytes) {
    422        if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
    423            return dstInit;
    424        }
    425        if ((nBytes - 1) * 8 + dstPos >= 32) {
    426            throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 32");
    427        }
    428        int out = dstInit;
    429        for (int i = 0; i < nBytes; i++) {
    430            final int shift = i * 8 + dstPos;
    431            final int bits = (0xff & src[i + srcPos]) << shift;
    432            final int mask = 0xff << shift;
    433            out = out & ~mask | bits;
    434        }
    435        return out;
    436    }
    437
    438    /**
    439     * Converts an array of byte into a long using the default (little-endian, Lsb0) byte and
    440     * bit ordering.
    441     *
    442     * @param src the byte array to convert
    443     * @param srcPos the position in {@code src}, in byte unit, from where to start the
    444     *            conversion
    445     * @param dstInit initial value of the destination long
    446     * @param dstPos the position of the lsb, in bits, in the result long
    447     * @param nBytes the number of bytes to convert
    448     * @return a long containing the selected bits
    449     * @throws NullPointerException if {@code src} is {@code null}
    450     * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 64}
    451     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
    452     */
    453    public static long byteArrayToLong(final byte[] src, final int srcPos, final long dstInit, final int dstPos,
    454            final int nBytes) {
    455        if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
    456            return dstInit;
    457        }
    458        if ((nBytes - 1) * 8 + dstPos >= 64) {
    459            throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 64");
    460        }
    461        long out = dstInit;
    462        for (int i = 0; i < nBytes; i++) {
    463            final int shift = i * 8 + dstPos;
    464            final long bits = (0xffL & src[i + srcPos]) << shift;
    465            final long mask = 0xffL << shift;
    466            out = out & ~mask | bits;
    467        }
    468        return out;
    469    }
    470
    471    /**
    472     * Converts an array of byte into a short using the default (little-endian, Lsb0) byte and
    473     * bit ordering.
    474     *
    475     * @param src the byte array to convert
    476     * @param srcPos the position in {@code src}, in byte unit, from where to start the
    477     *            conversion
    478     * @param dstInit initial value of the destination short
    479     * @param dstPos the position of the lsb, in bits, in the result short
    480     * @param nBytes the number of bytes to convert
    481     * @return a short containing the selected bits
    482     * @throws NullPointerException if {@code src} is {@code null}
    483     * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 16}
    484     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
    485     */
    486    public static short byteArrayToShort(final byte[] src, final int srcPos, final short dstInit, final int dstPos,
    487            final int nBytes) {
    488        if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
    489            return dstInit;
    490        }
    491        if ((nBytes - 1) * 8 + dstPos >= 16) {
    492            throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 16");
    493        }
    494        short out = dstInit;
    495        for (int i = 0; i < nBytes; i++) {
    496            final int shift = i * 8 + dstPos;
    497            final int bits = (0xff & src[i + srcPos]) << shift;
    498            final int mask = 0xff << shift;
    499            out = (short) (out & ~mask | bits);
    500        }
    501        return out;
    502    }
    503
    504    /**
    505     * Converts bytes from an array into a UUID using the default (little-endian, Lsb0) byte and
    506     * bit ordering.
    507     *
    508     * @param src the byte array to convert
    509     * @param srcPos the position in {@code src} where to copy the result from
    510     * @return a UUID
    511     * @throws NullPointerException if {@code src} is {@code null}
    512     * @throws IllegalArgumentException if array does not contain at least 16 bytes beginning
    513     *             with {@code srcPos}
    514     */
    515    public static UUID byteArrayToUuid(final byte[] src, final int srcPos) {
    516        if (src.length - srcPos < 16) {
    517            throw new IllegalArgumentException("Need at least 16 bytes for UUID");
    518        }
    519        return new UUID(byteArrayToLong(src, srcPos, 0, 0, 8), byteArrayToLong(src, srcPos + 8, 0, 0, 8));
    520    }
    521
    522    /**
    523     * Converts a byte into an array of boolean using the default (little-endian, Lsb0) byte and
    524     * bit ordering.
    525     *
    526     * @param src the byte to convert
    527     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    528     * @param dst the destination array
    529     * @param dstPos the position in {@code dst} where to copy the result
    530     * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
    531     *            the width of the input (from srcPos to msb)
    532     * @return {@code dst}
    533     * @throws NullPointerException if {@code dst} is {@code null}
    534     * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 8}
    535     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
    536     */
    537    public static boolean[] byteToBinary(final byte src, final int srcPos, final boolean[] dst, final int dstPos,
    538            final int nBools) {
    539        if (0 == nBools) {
    540            return dst;
    541        }
    542        if (nBools - 1 + srcPos >= 8) {
    543            throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 8");
    544        }
    545        for (int i = 0; i < nBools; i++) {
    546            final int shift = i + srcPos;
    547            dst[dstPos + i] = (0x1 & src >> shift) != 0;
    548        }
    549        return dst;
    550    }
    551
    552    /**
    553     * Converts a byte into an array of Char using the default (little-endian, Lsb0) byte and
    554     * bit ordering.
    555     *
    556     * @param src the byte to convert
    557     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    558     * @param dstInit the initial value for the result String
    559     * @param dstPos the position in {@code dst} where to copy the result
    560     * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
    561     *            width of the input (from srcPos to msb)
    562     * @return {@code dst}
    563     * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 8}
    564     * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
    565     */
    566    public static String byteToHex(final byte src, final int srcPos, final String dstInit, final int dstPos,
    567            final int nHexs) {
    568        if (0 == nHexs) {
    569            return dstInit;
    570        }
    571        if ((nHexs - 1) * 4 + srcPos >= 8) {
    572            throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 8");
    573        }
    574        final StringBuilder sb = new StringBuilder(dstInit);
    575        int append = sb.length();
    576        for (int i = 0; i < nHexs; i++) {
    577            final int shift = i * 4 + srcPos;
    578            final int bits = 0xF & src >> shift;
    579            if (dstPos + i == append) {
    580                ++append;
    581                sb.append(intToHexDigit(bits));
    582            } else {
    583                sb.setCharAt(dstPos + i, intToHexDigit(bits));
    584            }
    585        }
    586        return sb.toString();
    587    }
    588
    589    /**
    590     * Converts a hexadecimal digit into binary (represented as boolean array) using the Msb0
    591     * bit ordering.
    592     *
    593     * <p>
    594     * '1' is converted as follow: (0, 0, 0, 1)
    595     * </p>
    596     *
    597     * @param hexDigit the hexadecimal digit to convert
    598     * @return a boolean array with the binary representation of {@code hexDigit}
    599     * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
    600     */
    601    public static boolean[] hexDigitMsb0ToBinary(final char hexDigit) {
    602        switch (hexDigit) {
    603        case '0':
    604            return FFFF.clone();
    605        case '1':
    606            return FFFT.clone();
    607        case '2':
    608            return FFTF.clone();
    609        case '3':
    610            return FFTT.clone();
    611        case '4':
    612            return FTFF.clone();
    613        case '5':
    614            return FTFT.clone();
    615        case '6':
    616            return FTTF.clone();
    617        case '7':
    618            return FTTT.clone();
    619        case '8':
    620            return TFFF.clone();
    621        case '9':
    622            return TFFT.clone();
    623        case 'a':// fall through
    624        case 'A':
    625            return TFTF.clone();
    626        case 'b':// fall through
    627        case 'B':
    628            return TFTT.clone();
    629        case 'c':// fall through
    630        case 'C':
    631            return TTFF.clone();
    632        case 'd':// fall through
    633        case 'D':
    634            return TTFT.clone();
    635        case 'e':// fall through
    636        case 'E':
    637            return TTTF.clone();
    638        case 'f':// fall through
    639        case 'F':
    640            return TTTT.clone();
    641        default:
    642            throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
    643        }
    644    }
    645
    646    /**
    647     * Converts a hexadecimal digit into an int using the Msb0 bit ordering.
    648     *
    649     * <p>
    650     * '1' is converted to 8
    651     * </p>
    652     *
    653     * @param hexDigit the hexadecimal digit to convert
    654     * @return an int equals to {@code hexDigit}
    655     * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
    656     */
    657    public static int hexDigitMsb0ToInt(final char hexDigit) {
    658        switch (hexDigit) {
    659        case '0':
    660            return 0x0;
    661        case '1':
    662            return 0x8;
    663        case '2':
    664            return 0x4;
    665        case '3':
    666            return 0xC;
    667        case '4':
    668            return 0x2;
    669        case '5':
    670            return 0xA;
    671        case '6':
    672            return 0x6;
    673        case '7':
    674            return 0xE;
    675        case '8':
    676            return 0x1;
    677        case '9':
    678            return 0x9;
    679        case 'a':// fall through
    680        case 'A':
    681            return 0x5;
    682        case 'b':// fall through
    683        case 'B':
    684            return 0xD;
    685        case 'c':// fall through
    686        case 'C':
    687            return 0x3;
    688        case 'd':// fall through
    689        case 'D':
    690            return 0xB;
    691        case 'e':// fall through
    692        case 'E':
    693            return 0x7;
    694        case 'f':// fall through
    695        case 'F':
    696            return 0xF;
    697        default:
    698            throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
    699        }
    700    }
    701
    702    /**
    703     * Converts a hexadecimal digit into binary (represented as boolean array) using the default
    704     * (Lsb0) bit ordering.
    705     *
    706     * <p>
    707     * '1' is converted as follow: (1, 0, 0, 0)
    708     * </p>
    709     *
    710     * @param hexDigit the hexadecimal digit to convert
    711     * @return a boolean array with the binary representation of {@code hexDigit}
    712     * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
    713     */
    714    public static boolean[] hexDigitToBinary(final char hexDigit) {
    715        switch (hexDigit) {
    716        case '0':
    717            return FFFF.clone();
    718        case '1':
    719            return TFFF.clone();
    720        case '2':
    721            return FTFF.clone();
    722        case '3':
    723            return TTFF.clone();
    724        case '4':
    725            return FFTF.clone();
    726        case '5':
    727            return TFTF.clone();
    728        case '6':
    729            return FTTF.clone();
    730        case '7':
    731            return TTTF.clone();
    732        case '8':
    733            return FFFT.clone();
    734        case '9':
    735            return TFFT.clone();
    736        case 'a':// fall through
    737        case 'A':
    738            return FTFT.clone();
    739        case 'b':// fall through
    740        case 'B':
    741            return TTFT.clone();
    742        case 'c':// fall through
    743        case 'C':
    744            return FFTT.clone();
    745        case 'd':// fall through
    746        case 'D':
    747            return TFTT.clone();
    748        case 'e':// fall through
    749        case 'E':
    750            return FTTT.clone();
    751        case 'f':// fall through
    752        case 'F':
    753            return TTTT.clone();
    754        default:
    755            throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
    756        }
    757    }
    758
    759    /**
    760     * Converts a hexadecimal digit into an int using the default (Lsb0) bit ordering.
    761     *
    762     * <p>
    763     * '1' is converted to 1
    764     * </p>
    765     *
    766     * @param hexDigit the hexadecimal digit to convert
    767     * @return an int equals to {@code hexDigit}
    768     * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
    769     */
    770    public static int hexDigitToInt(final char hexDigit) {
    771        final int digit = Character.digit(hexDigit, 16);
    772        if (digit < 0) {
    773            throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
    774        }
    775        return digit;
    776    }
    777
    778    /**
    779     * Converts a hexadecimal string into a byte using the default (little-endian, Lsb0) byte and
    780     * bit ordering.
    781     *
    782     * @param src the hexadecimal string to convert
    783     * @param srcPos the position in {@code src}, in Char unit, from where to start the
    784     *            conversion
    785     * @param dstInit initial value of the destination byte
    786     * @param dstPos the position of the lsb, in bits, in the result byte
    787     * @param nHex the number of Chars to convert
    788     * @return a byte containing the selected bits
    789     * @throws IllegalArgumentException if {@code (nHex-1)*4+dstPos >= 8}
    790     */
    791    public static byte hexToByte(final String src, final int srcPos, final byte dstInit, final int dstPos,
    792            final int nHex) {
    793        if (0 == nHex) {
    794            return dstInit;
    795        }
    796        if ((nHex - 1) * 4 + dstPos >= 8) {
    797            throw new IllegalArgumentException("(nHex-1)*4+dstPos is greater than or equal to 8");
    798        }
    799        byte out = dstInit;
    800        for (int i = 0; i < nHex; i++) {
    801            final int shift = i * 4 + dstPos;
    802            final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
    803            final int mask = 0xf << shift;
    804            out = (byte) (out & ~mask | bits);
    805        }
    806        return out;
    807    }
    808
    809    /**
    810     * Converts an array of Char into an int using the default (little-endian, Lsb0) byte and bit
    811     * ordering.
    812     *
    813     * @param src the hexadecimal string to convert
    814     * @param srcPos the position in {@code src}, in Char unit, from where to start the
    815     *            conversion
    816     * @param dstInit initial value of the destination int
    817     * @param dstPos the position of the lsb, in bits, in the result int
    818     * @param nHex the number of Chars to convert
    819     * @return an int containing the selected bits
    820     * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 32}
    821     */
    822    public static int hexToInt(final String src, final int srcPos, final int dstInit, final int dstPos, final int nHex) {
    823        if (0 == nHex) {
    824            return dstInit;
    825        }
    826        if ((nHex - 1) * 4 + dstPos >= 32) {
    827            throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 32");
    828        }
    829        int out = dstInit;
    830        for (int i = 0; i < nHex; i++) {
    831            final int shift = i * 4 + dstPos;
    832            final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
    833            final int mask = 0xf << shift;
    834            out = out & ~mask | bits;
    835        }
    836        return out;
    837    }
    838
    839    /**
    840     * Converts an array of Char into a long using the default (little-endian, Lsb0) byte and
    841     * bit ordering.
    842     *
    843     * @param src the hexadecimal string to convert
    844     * @param srcPos the position in {@code src}, in Char unit, from where to start the
    845     *            conversion
    846     * @param dstInit initial value of the destination long
    847     * @param dstPos the position of the lsb, in bits, in the result long
    848     * @param nHex the number of Chars to convert
    849     * @return a long containing the selected bits
    850     * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 64}
    851     */
    852    public static long hexToLong(final String src, final int srcPos, final long dstInit, final int dstPos,
    853            final int nHex) {
    854        if (0 == nHex) {
    855            return dstInit;
    856        }
    857        if ((nHex - 1) * 4 + dstPos >= 64) {
    858            throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 64");
    859        }
    860        long out = dstInit;
    861        for (int i = 0; i < nHex; i++) {
    862            final int shift = i * 4 + dstPos;
    863            final long bits = (0xfL & hexDigitToInt(src.charAt(i + srcPos))) << shift;
    864            final long mask = 0xfL << shift;
    865            out = out & ~mask | bits;
    866        }
    867        return out;
    868    }
    869
    870    /**
    871     * Converts an array of Char into a short using the default (little-endian, Lsb0) byte and
    872     * bit ordering.
    873     *
    874     * @param src the hexadecimal string to convert
    875     * @param srcPos the position in {@code src}, in Char unit, from where to start the
    876     *            conversion
    877     * @param dstInit initial value of the destination short
    878     * @param dstPos the position of the lsb, in bits, in the result short
    879     * @param nHex the number of Chars to convert
    880     * @return a short containing the selected bits
    881     * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 16}
    882     */
    883    public static short hexToShort(final String src, final int srcPos, final short dstInit, final int dstPos,
    884            final int nHex) {
    885        if (0 == nHex) {
    886            return dstInit;
    887        }
    888        if ((nHex - 1) * 4 + dstPos >= 16) {
    889            throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 16");
    890        }
    891        short out = dstInit;
    892        for (int i = 0; i < nHex; i++) {
    893            final int shift = i * 4 + dstPos;
    894            final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
    895            final int mask = 0xf << shift;
    896            out = (short) (out & ~mask | bits);
    897        }
    898        return out;
    899    }
    900
    901    /**
    902     * Converts an array of int into a long using the default (little-endian, Lsb0) byte and bit
    903     * ordering.
    904     *
    905     * @param src the int array to convert
    906     * @param srcPos the position in {@code src}, in int unit, from where to start the
    907     *            conversion
    908     * @param dstInit initial value of the destination long
    909     * @param dstPos the position of the lsb, in bits, in the result long
    910     * @param nInts the number of ints to convert
    911     * @return a long containing the selected bits
    912     * @throws IllegalArgumentException if {@code (nInts-1)*32+dstPos >= 64}
    913     * @throws NullPointerException if {@code src} is {@code null}
    914     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nInts > src.length}
    915     */
    916    public static long intArrayToLong(final int[] src, final int srcPos, final long dstInit, final int dstPos,
    917            final int nInts) {
    918        if (src.length == 0 && srcPos == 0 || 0 == nInts) {
    919            return dstInit;
    920        }
    921        if ((nInts - 1) * 32 + dstPos >= 64) {
    922            throw new IllegalArgumentException("(nInts-1)*32+dstPos is greater or equal to than 64");
    923        }
    924        long out = dstInit;
    925        for (int i = 0; i < nInts; i++) {
    926            final int shift = i * 32 + dstPos;
    927            final long bits = (0xffffffffL & src[i + srcPos]) << shift;
    928            final long mask = 0xffffffffL << shift;
    929            out = out & ~mask | bits;
    930        }
    931        return out;
    932    }
    933
    934    /**
    935     * Converts an int into an array of boolean using the default (little-endian, Lsb0) byte and
    936     * bit ordering.
    937     *
    938     * @param src the int to convert
    939     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    940     * @param dst the destination array
    941     * @param dstPos the position in {@code dst} where to copy the result
    942     * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
    943     *            the width of the input (from srcPos to msb)
    944     * @return {@code dst}
    945     * @throws NullPointerException if {@code dst} is {@code null}
    946     * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 32}
    947     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
    948     */
    949    public static boolean[] intToBinary(final int src, final int srcPos, final boolean[] dst, final int dstPos,
    950            final int nBools) {
    951        if (0 == nBools) {
    952            return dst;
    953        }
    954        if (nBools - 1 + srcPos >= 32) {
    955            throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 32");
    956        }
    957        for (int i = 0; i < nBools; i++) {
    958            final int shift = i + srcPos;
    959            dst[dstPos + i] = (0x1 & src >> shift) != 0;
    960        }
    961        return dst;
    962    }
    963
    964    /**
    965     * Converts an int into an array of byte using the default (little-endian, Lsb0) byte and bit
    966     * ordering.
    967     *
    968     * @param src the int to convert
    969     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    970     * @param dst the destination array
    971     * @param dstPos the position in {@code dst} where to copy the result
    972     * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
    973     *            width of the input (from srcPos to msb)
    974     * @return {@code dst}
    975     * @throws NullPointerException if {@code dst} is {@code null}
    976     * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 32}
    977     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
    978     */
    979    public static byte[] intToByteArray(final int src, final int srcPos, final byte[] dst, final int dstPos,
    980            final int nBytes) {
    981        if (0 == nBytes) {
    982            return dst;
    983        }
    984        if ((nBytes - 1) * 8 + srcPos >= 32) {
    985            throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 32");
    986        }
    987        for (int i = 0; i < nBytes; i++) {
    988            final int shift = i * 8 + srcPos;
    989            dst[dstPos + i] = (byte) (0xff & src >> shift);
    990        }
    991        return dst;
    992    }
    993
    994    /**
    995     * Converts an int into an array of Char using the default (little-endian, Lsb0) byte and bit
    996     * ordering.
    997     *
    998     * @param src the int to convert
    999     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1000     * @param dstInit the initial value for the result String
    1001     * @param dstPos the position in {@code dst} where to copy the result
    1002     * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
    1003     *            width of the input (from srcPos to msb)
    1004     * @return {@code dst}
    1005     * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 32}
    1006     * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
    1007     */
    1008    public static String intToHex(final int src, final int srcPos, final String dstInit, final int dstPos,
    1009            final int nHexs) {
    1010        if (0 == nHexs) {
    1011            return dstInit;
    1012        }
    1013        if ((nHexs - 1) * 4 + srcPos >= 32) {
    1014            throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 32");
    1015        }
    1016        final StringBuilder sb = new StringBuilder(dstInit);
    1017        int append = sb.length();
    1018        for (int i = 0; i < nHexs; i++) {
    1019            final int shift = i * 4 + srcPos;
    1020            final int bits = 0xF & src >> shift;
    1021            if (dstPos + i == append) {
    1022                ++append;
    1023                sb.append(intToHexDigit(bits));
    1024            } else {
    1025                sb.setCharAt(dstPos + i, intToHexDigit(bits));
    1026            }
    1027        }
    1028        return sb.toString();
    1029    }
    1030
    1031    /**
    1032     * Converts the 4 lsb of an int to a hexadecimal digit.
    1033     *
    1034     * <p>
    1035     * 0 returns '0'
    1036     * </p>
    1037     * <p>
    1038     * 1 returns '1'
    1039     * </p>
    1040     * <p>
    1041     * 10 returns 'A' and so on...
    1042     * </p>
    1043     *
    1044     * @param nibble the 4 bits to convert
    1045     * @return a hexadecimal digit representing the 4 lsb of {@code nibble}
    1046     * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}
    1047     */
    1048    public static char intToHexDigit(final int nibble) {
    1049        final char c = Character.forDigit(nibble, 16);
    1050        if (c == Character.MIN_VALUE) {
    1051            throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
    1052        }
    1053        return c;
    1054    }
    1055
    1056    /**
    1057     * Converts the 4 lsb of an int to a hexadecimal digit encoded using the Msb0 bit ordering.
    1058     *
    1059     * <p>
    1060     * 0 returns '0'
    1061     * </p>
    1062     * <p>
    1063     * 1 returns '8'
    1064     * </p>
    1065     * <p>
    1066     * 10 returns '5' and so on...
    1067     * </p>
    1068     *
    1069     * @param nibble the 4 bits to convert
    1070     * @return a hexadecimal digit representing the 4 lsb of {@code nibble}
    1071     * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}
    1072     */
    1073    public static char intToHexDigitMsb0(final int nibble) {
    1074        switch (nibble) {
    1075        case 0x0:
    1076            return '0';
    1077        case 0x1:
    1078            return '8';
    1079        case 0x2:
    1080            return '4';
    1081        case 0x3:
    1082            return 'c';
    1083        case 0x4:
    1084            return '2';
    1085        case 0x5:
    1086            return 'a';
    1087        case 0x6:
    1088            return '6';
    1089        case 0x7:
    1090            return 'e';
    1091        case 0x8:
    1092            return '1';
    1093        case 0x9:
    1094            return '9';
    1095        case 0xA:
    1096            return '5';
    1097        case 0xB:
    1098            return 'd';
    1099        case 0xC:
    1100            return '3';
    1101        case 0xD:
    1102            return 'b';
    1103        case 0xE:
    1104            return '7';
    1105        case 0xF:
    1106            return 'f';
    1107        default:
    1108            throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
    1109        }
    1110    }
    1111
    1112    /**
    1113     * Converts an int into an array of short using the default (little-endian, Lsb0) byte and
    1114     * bit ordering.
    1115     *
    1116     * @param src the int to convert
    1117     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1118     * @param dst the destination array
    1119     * @param dstPos the position in {@code dst} where to copy the result
    1120     * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to
    1121     *            the width of the input (from srcPos to msb)
    1122     * @return {@code dst}
    1123     * @throws NullPointerException if {@code dst} is {@code null}
    1124     * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 32}
    1125     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}
    1126     */
    1127    public static short[] intToShortArray(final int src, final int srcPos, final short[] dst, final int dstPos,
    1128            final int nShorts) {
    1129        if (0 == nShorts) {
    1130            return dst;
    1131        }
    1132        if ((nShorts - 1) * 16 + srcPos >= 32) {
    1133            throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 32");
    1134        }
    1135        for (int i = 0; i < nShorts; i++) {
    1136            final int shift = i * 16 + srcPos;
    1137            dst[dstPos + i] = (short) (0xffff & src >> shift);
    1138        }
    1139        return dst;
    1140    }
    1141
    1142    /**
    1143     * Converts a long into an array of boolean using the default (little-endian, Lsb0) byte and
    1144     * bit ordering.
    1145     *
    1146     * @param src the long to convert
    1147     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1148     * @param dst the destination array
    1149     * @param dstPos the position in {@code dst} where to copy the result
    1150     * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
    1151     *            the width of the input (from srcPos to msb)
    1152     * @return {@code dst}
    1153     * @throws NullPointerException if {@code dst} is {@code null}
    1154     * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 64}
    1155     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
    1156     */
    1157    public static boolean[] longToBinary(final long src, final int srcPos, final boolean[] dst, final int dstPos,
    1158            final int nBools) {
    1159        if (0 == nBools) {
    1160            return dst;
    1161        }
    1162        if (nBools - 1 + srcPos >= 64) {
    1163            throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 64");
    1164        }
    1165        for (int i = 0; i < nBools; i++) {
    1166            final int shift = i + srcPos;
    1167            dst[dstPos + i] = (0x1 & src >> shift) != 0;
    1168        }
    1169        return dst;
    1170    }
    1171
    1172    /**
    1173     * Converts a long into an array of byte using the default (little-endian, Lsb0) byte and
    1174     * bit ordering.
    1175     *
    1176     * @param src the long to convert
    1177     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1178     * @param dst the destination array
    1179     * @param dstPos the position in {@code dst} where to copy the result
    1180     * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
    1181     *            width of the input (from srcPos to msb)
    1182     * @return {@code dst}
    1183     * @throws NullPointerException if {@code dst} is {@code null}
    1184     * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 64}
    1185     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
    1186     */
    1187    public static byte[] longToByteArray(final long src, final int srcPos, final byte[] dst, final int dstPos,
    1188            final int nBytes) {
    1189        if (0 == nBytes) {
    1190            return dst;
    1191        }
    1192        if ((nBytes - 1) * 8 + srcPos >= 64) {
    1193            throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 64");
    1194        }
    1195        for (int i = 0; i < nBytes; i++) {
    1196            final int shift = i * 8 + srcPos;
    1197            dst[dstPos + i] = (byte) (0xff & src >> shift);
    1198        }
    1199        return dst;
    1200    }
    1201
    1202    /**
    1203     * Converts a long into an array of Char using the default (little-endian, Lsb0) byte and
    1204     * bit ordering.
    1205     *
    1206     * @param src the long to convert
    1207     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1208     * @param dstInit the initial value for the result String
    1209     * @param dstPos the position in {@code dst} where to copy the result
    1210     * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
    1211     *            width of the input (from srcPos to msb)
    1212     * @return {@code dst}
    1213     * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 64}
    1214     * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
    1215     */
    1216    public static String longToHex(final long src, final int srcPos, final String dstInit, final int dstPos,
    1217            final int nHexs) {
    1218        if (0 == nHexs) {
    1219            return dstInit;
    1220        }
    1221        if ((nHexs - 1) * 4 + srcPos >= 64) {
    1222            throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 64");
    1223        }
    1224        final StringBuilder sb = new StringBuilder(dstInit);
    1225        int append = sb.length();
    1226        for (int i = 0; i < nHexs; i++) {
    1227            final int shift = i * 4 + srcPos;
    1228            final int bits = (int) (0xF & src >> shift);
    1229            if (dstPos + i == append) {
    1230                ++append;
    1231                sb.append(intToHexDigit(bits));
    1232            } else {
    1233                sb.setCharAt(dstPos + i, intToHexDigit(bits));
    1234            }
    1235        }
    1236        return sb.toString();
    1237    }
    1238
    1239    /**
    1240     * Converts a long into an array of int using the default (little-endian, Lsb0) byte and bit
    1241     * ordering.
    1242     *
    1243     * @param src the long to convert
    1244     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1245     * @param dst the destination array
    1246     * @param dstPos the position in {@code dst} where to copy the result
    1247     * @param nInts the number of ints to copy to {@code dst}, must be smaller or equal to the
    1248     *            width of the input (from srcPos to msb)
    1249     * @return {@code dst}
    1250     * @throws NullPointerException if {@code dst} is {@code null} and {@code nInts > 0}
    1251     * @throws IllegalArgumentException if {@code (nInts-1)*32+srcPos >= 64}
    1252     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nInts > dst.length}
    1253     */
    1254    public static int[] longToIntArray(final long src, final int srcPos, final int[] dst, final int dstPos,
    1255            final int nInts) {
    1256        if (0 == nInts) {
    1257            return dst;
    1258        }
    1259        if ((nInts - 1) * 32 + srcPos >= 64) {
    1260            throw new IllegalArgumentException("(nInts-1)*32+srcPos is greater or equal to than 64");
    1261        }
    1262        for (int i = 0; i < nInts; i++) {
    1263            final int shift = i * 32 + srcPos;
    1264            dst[dstPos + i] = (int) (0xffffffff & src >> shift);
    1265        }
    1266        return dst;
    1267    }
    1268
    1269    /**
    1270     * Converts a long into an array of short using the default (little-endian, Lsb0) byte and
    1271     * bit ordering.
    1272     *
    1273     * @param src the long to convert
    1274     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1275     * @param dst the destination array
    1276     * @param dstPos the position in {@code dst} where to copy the result
    1277     * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to
    1278     *            the width of the input (from srcPos to msb)
    1279     * @return {@code dst}
    1280     * @throws NullPointerException if {@code dst} is {@code null}
    1281     * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 64}
    1282     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}
    1283     */
    1284    public static short[] longToShortArray(final long src, final int srcPos, final short[] dst, final int dstPos,
    1285            final int nShorts) {
    1286        if (0 == nShorts) {
    1287            return dst;
    1288        }
    1289        if ((nShorts - 1) * 16 + srcPos >= 64) {
    1290            throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 64");
    1291        }
    1292        for (int i = 0; i < nShorts; i++) {
    1293            final int shift = i * 16 + srcPos;
    1294            dst[dstPos + i] = (short) (0xffff & src >> shift);
    1295        }
    1296        return dst;
    1297    }
    1298
    1299    /**
    1300     * Converts an array of short into an int using the default (little-endian, Lsb0) byte and
    1301     * bit ordering.
    1302     *
    1303     * @param src the short array to convert
    1304     * @param srcPos the position in {@code src}, in short unit, from where to start the
    1305     *            conversion
    1306     * @param dstInit initial value of the destination int
    1307     * @param dstPos the position of the lsb, in bits, in the result int
    1308     * @param nShorts the number of shorts to convert
    1309     * @return an int containing the selected bits
    1310     * @throws NullPointerException if {@code src} is {@code null}
    1311     * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 32}
    1312     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}
    1313     */
    1314    public static int shortArrayToInt(final short[] src, final int srcPos, final int dstInit, final int dstPos,
    1315            final int nShorts) {
    1316        if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
    1317            return dstInit;
    1318        }
    1319        if ((nShorts - 1) * 16 + dstPos >= 32) {
    1320            throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 32");
    1321        }
    1322        int out = dstInit;
    1323        for (int i = 0; i < nShorts; i++) {
    1324            final int shift = i * 16 + dstPos;
    1325            final int bits = (0xffff & src[i + srcPos]) << shift;
    1326            final int mask = 0xffff << shift;
    1327            out = out & ~mask | bits;
    1328        }
    1329        return out;
    1330    }
    1331
    1332    /**
    1333     * Converts an array of short into a long using the default (little-endian, Lsb0) byte and
    1334     * bit ordering.
    1335     *
    1336     * @param src the short array to convert
    1337     * @param srcPos the position in {@code src}, in short unit, from where to start the
    1338     *            conversion
    1339     * @param dstInit initial value of the destination long
    1340     * @param dstPos the position of the lsb, in bits, in the result long
    1341     * @param nShorts the number of shorts to convert
    1342     * @return a long containing the selected bits
    1343     * @throws NullPointerException if {@code src} is {@code null}
    1344     * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 64}
    1345     * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}
    1346     */
    1347    public static long shortArrayToLong(final short[] src, final int srcPos, final long dstInit, final int dstPos,
    1348            final int nShorts) {
    1349        if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
    1350            return dstInit;
    1351        }
    1352        if ((nShorts - 1) * 16 + dstPos >= 64) {
    1353            throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 64");
    1354        }
    1355        long out = dstInit;
    1356        for (int i = 0; i < nShorts; i++) {
    1357            final int shift = i * 16 + dstPos;
    1358            final long bits = (0xffffL & src[i + srcPos]) << shift;
    1359            final long mask = 0xffffL << shift;
    1360            out = out & ~mask | bits;
    1361        }
    1362        return out;
    1363    }
    1364
    1365    /**
    1366     * Converts a short into an array of boolean using the default (little-endian, Lsb0) byte
    1367     * and bit ordering.
    1368     *
    1369     * @param src the short to convert
    1370     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1371     * @param dst the destination array
    1372     * @param dstPos the position in {@code dst} where to copy the result
    1373     * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
    1374     *            the width of the input (from srcPos to msb)
    1375     * @return {@code dst}
    1376     * @throws NullPointerException if {@code dst} is {@code null}
    1377     * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 16}
    1378     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
    1379     */
    1380    public static boolean[] shortToBinary(final short src, final int srcPos, final boolean[] dst, final int dstPos,
    1381            final int nBools) {
    1382        if (0 == nBools) {
    1383            return dst;
    1384        }
    1385        if (nBools - 1 + srcPos >= 16) {
    1386            throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 16");
    1387        }
    1388        assert nBools - 1 < 16 - srcPos;
    1389        for (int i = 0; i < nBools; i++) {
    1390            final int shift = i + srcPos;
    1391            dst[dstPos + i] = (0x1 & src >> shift) != 0;
    1392        }
    1393        return dst;
    1394    }
    1395
    1396    /**
    1397     * Converts a short into an array of byte using the default (little-endian, Lsb0) byte and
    1398     * bit ordering.
    1399     *
    1400     * @param src the short to convert
    1401     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1402     * @param dst the destination array
    1403     * @param dstPos the position in {@code dst} where to copy the result
    1404     * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
    1405     *            width of the input (from srcPos to msb)
    1406     * @return {@code dst}
    1407     * @throws NullPointerException if {@code dst} is {@code null}
    1408     * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 16}
    1409     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
    1410     */
    1411    public static byte[] shortToByteArray(final short src, final int srcPos, final byte[] dst, final int dstPos,
    1412            final int nBytes) {
    1413        if (0 == nBytes) {
    1414            return dst;
    1415        }
    1416        if ((nBytes - 1) * 8 + srcPos >= 16) {
    1417            throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 16");
    1418        }
    1419        for (int i = 0; i < nBytes; i++) {
    1420            final int shift = i * 8 + srcPos;
    1421            dst[dstPos + i] = (byte) (0xff & src >> shift);
    1422        }
    1423        return dst;
    1424    }
    1425
    1426    /**
    1427     * Converts a short into an array of Char using the default (little-endian, Lsb0) byte and
    1428     * bit ordering.
    1429     *
    1430     * @param src the short to convert
    1431     * @param srcPos the position in {@code src}, in bits, from where to start the conversion
    1432     * @param dstInit the initial value for the result String
    1433     * @param dstPos the position in {@code dst} where to copy the result
    1434     * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
    1435     *            width of the input (from srcPos to msb)
    1436     * @return {@code dst}
    1437     * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 16}
    1438     * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
    1439     */
    1440    public static String shortToHex(final short src, final int srcPos, final String dstInit, final int dstPos,
    1441            final int nHexs) {
    1442        if (0 == nHexs) {
    1443            return dstInit;
    1444        }
    1445        if ((nHexs - 1) * 4 + srcPos >= 16) {
    1446            throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 16");
    1447        }
    1448        final StringBuilder sb = new StringBuilder(dstInit);
    1449        int append = sb.length();
    1450        for (int i = 0; i < nHexs; i++) {
    1451            final int shift = i * 4 + srcPos;
    1452            final int bits = 0xF & src >> shift;
    1453            if (dstPos + i == append) {
    1454                ++append;
    1455                sb.append(intToHexDigit(bits));
    1456            } else {
    1457                sb.setCharAt(dstPos + i, intToHexDigit(bits));
    1458            }
    1459        }
    1460        return sb.toString();
    1461    }
    1462
    1463    /**
    1464     * Converts UUID into an array of byte using the default (little-endian, Lsb0) byte and bit
    1465     * ordering.
    1466     *
    1467     * @param src the UUID to convert
    1468     * @param dst the destination array
    1469     * @param dstPos the position in {@code dst} where to copy the result
    1470     * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
    1471     *            width of the input (from srcPos to msb)
    1472     * @return {@code dst}
    1473     * @throws NullPointerException if {@code dst} is {@code null}
    1474     * @throws IllegalArgumentException if {@code nBytes > 16}
    1475     * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
    1476     */
    1477    public static byte[] uuidToByteArray(final UUID src, final byte[] dst, final int dstPos, final int nBytes) {
    1478        if (0 == nBytes) {
    1479            return dst;
    1480        }
    1481        if (nBytes > 16) {
    1482            throw new IllegalArgumentException("nBytes is greater than 16");
    1483        }
    1484        longToByteArray(src.getMostSignificantBits(), 0, dst, dstPos, Math.min(nBytes, 8));
    1485        if (nBytes >= 8) {
    1486            longToByteArray(src.getLeastSignificantBits(), 0, dst, dstPos + 8, nBytes - 8);
    1487        }
    1488        return dst;
    1489    }
    1490
    1491    /**
    1492     * Constructs a new instance.
    1493     *
    1494     * @deprecated Will be removed in 4.0.0.
    1495     */
    1496    @Deprecated
    1497    public Conversion() {
    1498        // empty
    1499    }
    1500}