001    /* JAPI - (Yet another (hopefully) useful) Java API
002     *
003     * Copyright (C) 2004-2006 Christian Hujer
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License as
007     * published by the Free Software Foundation; either version 2 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful, but
011     * WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013     * General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018     * 02111-1307, USA.
019     */
020    
021    package net.sf.japi.io;
022    
023    /** A class to get nibbles from byte sequences.
024     * This class works in sequentially numbered big endian (network byte) order, which means that the first nibble (0-nibble) is the high nibble of the
025     * first byte (high byte high nibble).
026     * You may also call this "high nibble first".
027     * The long value 0x0123456789ABCDEFl reflects the nibble indices in longs.
028     * Other datatypes work similarly:
029     * The int value 0x01234567 reflects the nibble indices in ints.
030     * <p />
031     * Binary nibbles are returned as ints because the general contract of I/O-methods as in package <code>java.io</code> is to expect and return single
032     * bytes being stored in ints and it saves neither space nor performance to return bytes instead of ints.
033     * <p />
034     * When needing chars, you should invoke those methods returning chars directly (single method invocation) instead of first getting the nibble and then
035     * converting it to a char (two method invocations) because inlining compilers will give you a better performance then.
036     * <p />
037     * Everything in this class is final for performance reasons: Final methods can be sort of inlined by some compilers.
038     * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a>
039     */
040    @SuppressWarnings({"UtilityClass", "ClassWithTooManyMethods"})
041    public final class Nibbles {
042    
043        /** Lowercase nibble characters. */
044        private static final char[] LCASE_NIBBLES = "0123456789abcdef".toCharArray();
045    
046        /** Uppercase nibble characters. */
047        private static final char[] UCASE_NIBBLES = "0123456789ABCDEF".toCharArray();
048    
049        /** This class cannot be instanciated. */
050        private Nibbles() {}
051    
052        /** Get a nibble from a byte array.
053         * @param data byte array to get nibble from
054         * @param index nibble number
055         * @return nibble value with nibble number
056         */
057        public static int getNibble(final byte[] data, final int index) {
058            return getNibble(data[index >> 1], index & 1);
059        }
060    
061        /** Get all nibbles from a byte array.
062         * @param data byte array to get nibbles from
063         * @return byte array with nibbles; the length of the returned byte array is twice the length of the argument byte array
064         */
065        public static byte[] getNibbles(final byte[] data) {
066            return getNibbles(data, 0, data.length << 1);
067        }
068    
069        /** Get some nibbles from a byte array.
070         * @param data byte array to get nibbles from
071         * @param startIndex first nibble index to get nibble for
072         * @param length number of nibbles to get
073         * @return byte array with nibbles
074         */
075        public static byte[] getNibbles(final byte[] data, final int startIndex, final int length) {
076            if (length < 0) { throw new IllegalArgumentException("Length may not be negative: " + length); }
077            if (startIndex < 0) { throw new IllegalArgumentException("Start index may not be negative: " + startIndex); }
078            if (startIndex >> 1 > data.length) { throw new IllegalArgumentException("Start index out of range: " + startIndex); }
079            if (startIndex + length >> 1 > data.length) { throw new IllegalArgumentException("Length out of range: " + length); }
080            final byte[] nibbles = new byte[length];
081            for (int i = 0, j = startIndex; i < length; i++, j++) {
082                nibbles[i] = (byte) (0xF & data[j >> 1] >> 4 * (1 - j & 1));
083            }
084            return nibbles;
085        }
086    
087        /** Get a nibble from a byte value.
088         * @param data byte value to get nibble from
089         * @param index nibble number
090         * @return nibble value with nibble number
091         */
092        public static int getNibble(final byte data, final int index) {
093            return getNibble((long) data, index + 14);
094        }
095    
096        /** Get a nibble from a short value.
097         * @param data short value to get nibble from
098         * @param index nibble number
099         * @return nibble value with nibble number
100         */
101        public static int getNibble(final short data, final int index) {
102            return getNibble((long) data, index + 12);
103        }
104    
105        /** Get a nibble from an int value.
106         * @param data int value to get nibble from
107         * @param index nibble number
108         * @return nibble value with nibble number
109         */
110        public static int getNibble(final int data, final int index) {
111            return getNibble((long) data, index + 8);
112        }
113    
114        /** Get a nibble from a long value.
115         * @param data int value to get nibble from
116         * @param index nibble number
117         * @return nibble value with nibble number
118         */
119        public static int getNibble(final long data, final int index) {
120            return 0xF & (int) (data >> 4 * (15 - index));
121        }
122    
123        /** Get a nibble from a char value.
124         * @param data char value to get nibble from
125         * @param index nibble nubmer
126         * @return nibble value with nibble number
127         */
128        public static int getNibble(final char data, final int index) {
129            return getNibble((long) data, index + 12);
130        }
131    
132        /** Get a nibble from a float value (raw format).
133         * To get the nibble from a float value in logical format, convert the float to an int yourself using {@link Float#floatToIntBits(float)}.
134         * @param data float value to get nibble from
135         * @param index nibble nubmer
136         * @return nibble value with nibble number
137         */
138        public static int getNibble(final float data, final int index) {
139            return getNibble((long) Float.floatToRawIntBits(data), index + 8);
140        }
141    
142        /** Get a nibble from a double value (raw format).
143         * To get the nibble from a double value in logical format, convert the float to an int yourself using {@link Double#doubleToLongBits(double)}.
144         * @param data double value to get nibble from
145         * @param index nibble nubmer
146         * @return nibble value with nibble number
147         */
148        public static int getNibble(final double data, final int index) {
149            return getNibble(Double.doubleToRawLongBits(data), index);
150        }
151    
152        /** Get a lowercase character for a nibble.
153         * @param nibble nibble to get character for
154         * @return lowercase character for <var>data</var>
155         * @throws IllegalArgumentException if <code>data</code> isn't a single nibble
156         */
157        public static char getNibbleLC(final int nibble) {
158            try {
159                return LCASE_NIBBLES[nibble];
160            } catch (final ArrayIndexOutOfBoundsException ignore) {
161                throw new IllegalArgumentException("Not a nibble: " + nibble);
162            }
163        }
164    
165        /** Get a uppercase character for a nibble.
166         * @param nibble nibble to get character for
167         * @return uppercase character for <var>data</var>
168         * @throws IllegalArgumentException if <code>data</code> isn't a single nibble
169         */
170        public static char getNibbleUC(final int nibble) {
171            try {
172                return UCASE_NIBBLES[nibble];
173            } catch (final ArrayIndexOutOfBoundsException ignore) {
174                throw new IllegalArgumentException("Not a nibble: " + nibble);
175            }
176        }
177    
178        /** Get a lowercase character reflecting a nibble from a byte array.
179         * Shorthand for getNibbleLC(getNibble(data, index)).
180         * @param data byte array to get nibble from
181         * @param index nibble number
182         * @return nibble character
183         */
184        public static char getNibbleLC(final byte[] data, final int index) {
185            return getNibbleLC(getNibble(data, index));
186        }
187    
188        /** Get an uppercase character reflecting a nibble from a byte array.
189         * @param data byte array to get nibble from
190         * @param index nibble number
191         * @return nibble character
192         */
193        public static char getNibbleUC(final byte[] data, final int index) {
194            return getNibbleUC(getNibble(data, index));
195        }
196    
197        /** Get a lowercase character reflecting a nibble from a byte.
198         * Shorthand for getNibbleLC(getNibble(data, index)).
199         * @param data byte to get nibble from
200         * @param index nibble number
201         * @return nibble character
202         */
203        public static char getNibbleLC(final byte data, final int index) {
204            return getNibbleLC(getNibble(data, index));
205        }
206    
207        /** Get an uppercase character reflecting a nibble from a byte.
208         * @param data byte to get nibble from
209         * @param index nibble number
210         * @return nibble character
211         */
212        public static char getNibbleUC(final byte data, final int index) {
213            return getNibbleUC(getNibble(data, index));
214        }
215    
216        /** Get a lowercase character reflecting a nibble from a short.
217         * Shorthand for getNibbleLC(getNibble(data, index)).
218         * @param data short to get nibble from
219         * @param index nibble number
220         * @return nibble character
221         */
222        public static char getNibbleLC(final short data, final int index) {
223            return getNibbleLC(getNibble(data, index));
224        }
225    
226        /** Get an uppercase character reflecting a nibble from a short.
227         * @param data short to get nibble from
228         * @param index nibble number
229         * @return nibble character
230         */
231        public static char getNibbleUC(final short data, final int index) {
232            return getNibbleUC(getNibble(data, index));
233        }
234    
235        /** Get a lowercase character reflecting a nibble from a int.
236         * Shorthand for getNibbleLC(getNibble(data, index)).
237         * @param data int to get nibble from
238         * @param index nibble number
239         * @return nibble character
240         */
241        public static char getNibbleLC(final int data, final int index) {
242            return getNibbleLC(getNibble(data, index));
243        }
244    
245        /** Get an uppercase character reflecting a nibble from a int.
246         * @param data int to get nibble from
247         * @param index nibble number
248         * @return nibble character
249         */
250        public static char getNibbleUC(final int data, final int index) {
251            return getNibbleUC(getNibble(data, index));
252        }
253    
254        /** Get a lowercase character reflecting a nibble from a long.
255         * Shorthand for getNibbleLC(getNibble(data, index)).
256         * @param data long to get nibble from
257         * @param index nibble number
258         * @return nibble character
259         */
260        public static char getNibbleLC(final long data, final int index) {
261            return getNibbleLC(getNibble(data, index));
262        }
263    
264        /** Get an uppercase character reflecting a nibble from a long.
265         * @param data long to get nibble from
266         * @param index nibble number
267         * @return nibble character
268         */
269        public static char getNibbleUC(final long data, final int index) {
270            return getNibbleUC(getNibble(data, index));
271        }
272    
273        /** Get a lowercase character reflecting a nibble from a char.
274         * Shorthand for getNibbleLC(getNibble(data, index)).
275         * @param data char to get nibble from
276         * @param index nibble number
277         * @return nibble character
278         */
279        public static char getNibbleLC(final char data, final int index) {
280            return getNibbleLC(getNibble(data, index));
281        }
282    
283        /** Get an uppercase character reflecting a nibble from a char.
284         * @param data char to get nibble from
285         * @param index nibble number
286         * @return nibble character
287         */
288        public static char getNibbleUC(final char data, final int index) {
289            return getNibbleUC(getNibble(data, index));
290        }
291    
292        /** Get a lowercase character reflecting a nibble from a float.
293         * Shorthand for getNibbleLC(getNibble(data, index)).
294         * @param data float to get nibble from
295         * @param index nibble number
296         * @return nibble character
297         */
298        public static char getNibbleLC(final float data, final int index) {
299            return getNibbleLC(getNibble(data, index));
300        }
301    
302        /** Get an uppercase character reflecting a nibble from a float.
303         * @param data float to get nibble from
304         * @param index nibble number
305         * @return nibble character
306         */
307        public static char getNibbleUC(final float data, final int index) {
308            return getNibbleUC(getNibble(data, index));
309        }
310    
311        /** Get a lowercase character reflecting a nibble from a double.
312         * Shorthand for getNibbleLC(getNibble(data, index)).
313         * @param data double to get nibble from
314         * @param index nibble number
315         * @return nibble character
316         */
317        public static char getNibbleLC(final double data, final int index) {
318            return getNibbleLC(getNibble(data, index));
319        }
320    
321        /** Get an uppercase character reflecting a nibble from a double.
322         * @param data double to get nibble from
323         * @param index nibble number
324         * @return nibble character
325         */
326        public static char getNibbleUC(final double data, final int index) {
327            return getNibbleUC(getNibble(data, index));
328        }
329    
330    } // class Nibbles