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