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