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