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